// AP Automation System
// Vendor invoice intake → approval → payment scheduling

import prisma from '@/lib/db';
import { logSimpleAction } from './agent-logger';

export interface InvoiceIntakeResult {
  invoiceId: string;
  invoiceNumber: string;
  vendorName: string;
  amount: number;
  status: string;
  autoApproved: boolean;
}

export interface ApprovalThresholds {
  autoApproveLimit: number;     // Auto-approve invoices below this amount
  requireDualApproval: number;  // Require dual approval above this amount
  maxSingleApproval: number;    // Max amount for single approval
}

const DEFAULT_THRESHOLDS: ApprovalThresholds = {
  autoApproveLimit: 500,
  requireDualApproval: 5000,
  maxSingleApproval: 10000,
};

// Create or get vendor
export async function getOrCreateVendor(vendorData: {
  name: string;
  email?: string;
  category?: string;
}): Promise<string> {
  let vendor = await prisma.vendor.findFirst({
    where: { name: vendorData.name },
  });
  
  if (!vendor) {
    vendor = await prisma.vendor.create({
      data: {
        name: vendorData.name,
        contactEmail: vendorData.email,
        category: vendorData.category || 'general',
      },
    });
  }
  
  return vendor.id;
}

// Intake a new vendor invoice
export async function intakeInvoice(data: {
  invoiceNumber: string;
  vendorName: string;
  vendorEmail?: string;
  amount: number;
  dueDate: Date;
  description?: string;
  lineItems?: { description: string; amount: number; quantity?: number }[];
  category?: string;
}): Promise<InvoiceIntakeResult> {
  // Get or create vendor
  const vendorId = await getOrCreateVendor({
    name: data.vendorName,
    email: data.vendorEmail,
    category: data.category,
  });
  
  // Check if invoice already exists
  const existing = await prisma.vendorInvoice.findUnique({
    where: { invoiceNumber: data.invoiceNumber },
  });
  
  if (existing) {
    return {
      invoiceId: existing.id,
      invoiceNumber: existing.invoiceNumber,
      vendorName: data.vendorName,
      amount: existing.amount,
      status: existing.status,
      autoApproved: false,
    };
  }
  
  // Check for auto-approval
  const autoApprove = data.amount <= DEFAULT_THRESHOLDS.autoApproveLimit;
  
  // Create invoice
  const invoice = await prisma.vendorInvoice.create({
    data: {
      invoiceNumber: data.invoiceNumber,
      vendorId,
      amount: data.amount,
      dueDate: data.dueDate,
      description: data.description,
      category: data.category || 'uncategorized',
      lineItems: data.lineItems ? JSON.parse(JSON.stringify(data.lineItems)) : [],
      status: autoApprove ? 'approved' : 'pending',
      approvedBy: autoApprove ? 'APAgent' : undefined,
      approvedAt: autoApprove ? new Date() : undefined,
    },
  });
  
  // Log agent action
  await logSimpleAction({
    actionType: 'create_transaction',
    targetEntity: 'VendorInvoice',
    targetId: invoice.id,
    input: { invoiceNumber: data.invoiceNumber, vendor: data.vendorName, amount: data.amount },
    output: { status: invoice.status, autoApproved: autoApprove },
    confidence: autoApprove ? 0.95 : 1.0,
    anomalyDetected: data.amount > DEFAULT_THRESHOLDS.requireDualApproval,
    anomalyType: data.amount > DEFAULT_THRESHOLDS.requireDualApproval ? 'high_value_invoice' : undefined,
  });
  
  return {
    invoiceId: invoice.id,
    invoiceNumber: invoice.invoiceNumber,
    vendorName: data.vendorName,
    amount: invoice.amount,
    status: invoice.status,
    autoApproved: autoApprove,
  };
}

// Approve an invoice
export async function approveInvoice(
  invoiceId: string,
  approvedBy: string,
  schedulePayDate?: Date
): Promise<void> {
  const invoice = await prisma.vendorInvoice.findUnique({
    where: { id: invoiceId },
    include: { vendor: true },
  });
  
  if (!invoice) throw new Error(`Invoice ${invoiceId} not found`);
  
  // Calculate payment date based on vendor terms
  let payDate = schedulePayDate;
  if (!payDate) {
    const termDays = invoice.vendor.paymentTerms === 'net-15' ? 15 :
                     invoice.vendor.paymentTerms === 'net-60' ? 60 :
                     invoice.vendor.paymentTerms === 'due-on-receipt' ? 0 : 30;
    payDate = new Date(invoice.dueDate.getTime() - termDays * 24 * 60 * 60 * 1000);
    if (payDate < new Date()) payDate = invoice.dueDate;
  }
  
  await prisma.vendorInvoice.update({
    where: { id: invoiceId },
    data: {
      status: 'scheduled',
      approvedBy,
      approvedAt: new Date(),
      scheduledPayDate: payDate,
    },
  });
  
  await logSimpleAction({
    actionType: 'update_ar',
    targetEntity: 'VendorInvoice',
    targetId: invoiceId,
    input: { approvedBy },
    output: { status: 'scheduled', scheduledPayDate: payDate },
    confidence: 1.0,
    anomalyDetected: false,
  });
}

// Process scheduled payments
export async function processScheduledPayments(): Promise<{
  processed: number;
  totalPaid: number;
  details: { invoiceNumber: string; vendor: string; amount: number }[];
}> {
  const today = new Date();
  today.setHours(23, 59, 59, 999);
  
  const dueInvoices = await prisma.vendorInvoice.findMany({
    where: {
      status: 'scheduled',
      scheduledPayDate: { lte: today },
    },
    include: { vendor: true },
  });
  
  const details: { invoiceNumber: string; vendor: string; amount: number }[] = [];
  let totalPaid = 0;
  
  for (const invoice of dueInvoices) {
    // Mark as paid (in real system, would trigger actual payment)
    await prisma.vendorInvoice.update({
      where: { id: invoice.id },
      data: {
        status: 'paid',
        paidAt: new Date(),
      },
    });
    
    // Create expense record
    await prisma.expense.create({
      data: {
        description: `Payment: ${invoice.invoiceNumber} - ${invoice.vendor.name}`,
        amount: invoice.amount,
        date: new Date(),
        category: invoice.category,
        vendor: invoice.vendor.name,
        paymentMethod: 'bank_transfer',
        status: 'categorized',
        aiCategorized: true,
        aiConfidence: 0.95,
        aiReasoning: `Auto-categorized from vendor invoice ${invoice.invoiceNumber}`,
      },
    });
    
    // Log the payment action (transaction created via expense record)
    await logSimpleAction({
      actionType: 'process_payment',
      targetEntity: 'VendorInvoice',
      targetId: invoice.id,
      input: { invoiceNumber: invoice.invoiceNumber },
      output: { paid: true, amount: invoice.amount },
      confidence: 1.0,
      anomalyDetected: false,
    });
    
    details.push({
      invoiceNumber: invoice.invoiceNumber,
      vendor: invoice.vendor.name,
      amount: invoice.amount,
    });
    totalPaid += invoice.amount;
  }
  
  return { processed: details.length, totalPaid, details };
}

// Get AP dashboard stats
export async function getAPStats(): Promise<{
  pendingApproval: number;
  pendingAmount: number;
  scheduledPayments: number;
  scheduledAmount: number;
  overdueCount: number;
  overdueAmount: number;
  paidThisMonth: number;
  paidAmountThisMonth: number;
}> {
  const now = new Date();
  const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
  
  const [pending, scheduled, overdue, paidThisMonth] = await Promise.all([
    prisma.vendorInvoice.findMany({ where: { status: 'pending' } }),
    prisma.vendorInvoice.findMany({ where: { status: 'scheduled' } }),
    prisma.vendorInvoice.findMany({
      where: {
        status: { in: ['pending', 'approved'] },
        dueDate: { lt: now },
      },
    }),
    prisma.vendorInvoice.findMany({
      where: {
        status: 'paid',
        paidAt: { gte: startOfMonth },
      },
    }),
  ]);
  
  return {
    pendingApproval: pending.length,
    pendingAmount: pending.reduce((sum: number, i: { amount: number }) => sum + i.amount, 0),
    scheduledPayments: scheduled.length,
    scheduledAmount: scheduled.reduce((sum: number, i: { amount: number }) => sum + i.amount, 0),
    overdueCount: overdue.length,
    overdueAmount: overdue.reduce((sum: number, i: { amount: number }) => sum + i.amount, 0),
    paidThisMonth: paidThisMonth.length,
    paidAmountThisMonth: paidThisMonth.reduce((sum: number, i: { amount: number }) => sum + i.amount, 0),
  };
}

// Get recent invoices
export async function getRecentInvoices(limit: number = 20): Promise<{
  id: string;
  invoiceNumber: string;
  vendorName: string;
  amount: number;
  status: string;
  dueDate: Date;
  createdAt: Date;
}[]> {
  const invoices = await prisma.vendorInvoice.findMany({
    take: limit,
    orderBy: { createdAt: 'desc' },
    include: { vendor: true },
  });
  
  return invoices.map((inv: any) => ({
    id: inv.id,
    invoiceNumber: inv.invoiceNumber,
    vendorName: inv.vendor.name,
    amount: inv.amount,
    status: inv.status,
    dueDate: inv.dueDate,
    createdAt: inv.createdAt,
  }));
}
