import { accounting } from "@/lib/accountingClient";

export type AutoBillSettings = {
  enabled: boolean;
  prompt_on_match: boolean;
  date_window_days: number;
  amount_tolerance_pct: number;
};

const DEFAULTS: AutoBillSettings = {
  enabled: true,
  prompt_on_match: true,
  date_window_days: 60,
  amount_tolerance_pct: 5,
};

export async function getAutoBillSettings(companyId: string): Promise<AutoBillSettings> {
  const { data } = await accounting
    .from("auto_bill_settings")
    .select("*")
    .eq("company_id", companyId)
    .maybeSingle();
  if (!data) return DEFAULTS;
  return {
    enabled: data.enabled,
    prompt_on_match: data.prompt_on_match,
    date_window_days: data.date_window_days,
    amount_tolerance_pct: data.amount_tolerance_pct,
  };
}

export async function upsertAutoBillSettings(companyId: string, s: Partial<AutoBillSettings>) {
  const current = await getAutoBillSettings(companyId);
  const merged = { ...current, ...s, company_id: companyId };
  const { data: existing } = await accounting
    .from("auto_bill_settings")
    .select("id")
    .eq("company_id", companyId)
    .maybeSingle();
  if (existing) {
    return accounting.from("auto_bill_settings").update(merged).eq("id", existing.id);
  }
  return accounting.from("auto_bill_settings").insert(merged);
}

export type PaymentPayload = {
  companyId: string;
  vendorId: string | null;
  amount: number;
  date: string; // YYYY-MM-DD
  category?: string | null;
  description?: string | null;
  sourceKind: "expense" | "check" | "transaction" | "journal";
  sourceId: string;
};

export async function findMatchingBills(p: PaymentPayload, s: AutoBillSettings) {
  if (!p.vendorId) return [];
  const start = new Date(p.date);
  start.setDate(start.getDate() - s.date_window_days);
  const end = new Date(p.date);
  end.setDate(end.getDate() + s.date_window_days);
  const { data } = await accounting
    .from("bills")
    .select("id, number, total, paid_amount, issue_date, status, vendor_id")
    .eq("company_id", p.companyId)
    .eq("vendor_id", p.vendorId)
    .gte("issue_date", start.toISOString().slice(0, 10))
    .lte("issue_date", end.toISOString().slice(0, 10))
    .in("status", ["open", "draft"]);
  const tol = s.amount_tolerance_pct / 100;
  return (data ?? []).filter((b: any) => {
    const balance = Number(b.total) - Number(b.paid_amount ?? 0);
    if (balance <= 0) return false;
    const diff = Math.abs(balance - p.amount);
    return diff <= Math.max(balance, p.amount) * tol;
  });
}

async function nextAutoNumber(companyId: string): Promise<string> {
  const { count } = await accounting
    .from("bills")
    .select("id", { count: "exact", head: true })
    .eq("company_id", companyId)
    .eq("auto_created", true);
  return `AUTO-BILL-${String((count ?? 0) + 1).padStart(4, "0")}`;
}

export async function createAutoBill(p: PaymentPayload): Promise<{ id: string; number: string } | null> {
  if (!p.vendorId) return null;
  const number = await nextAutoNumber(p.companyId);
  const { data: bill, error } = await accounting
    .from("bills")
    .insert({
      company_id: p.companyId,
      vendor_id: p.vendorId,
      number,
      issue_date: p.date,
      due_date: p.date,
      subtotal: p.amount,
      tax: 0,
      total: p.amount,
      paid_amount: p.amount,
      status: "paid",
      notes: `Auto-created from ${p.sourceKind} entry`,
      auto_created: true,
      source_payment_id: p.sourceId,
      source_payment_kind: p.sourceKind,
    })
    .select("id, number")
    .single();
  if (error || !bill) return null;
  await accounting.from("bill_items").insert({
    bill_id: bill.id,
    description: p.description || p.category || "Auto-created payment line",
    quantity: 1,
    rate: p.amount,
    amount: p.amount,
  });
  return bill;
}

export async function applyPaymentToBill(billId: string, amount: number) {
  const { data: bill } = await accounting.from("bills").select("total, paid_amount").eq("id", billId).single();
  if (!bill) return;
  const newPaid = Number(bill.paid_amount ?? 0) + amount;
  const status = newPaid >= Number(bill.total) ? "paid" : "open";
  await accounting.from("bills").update({ paid_amount: newPaid, status }).eq("id", billId);
}

/** Orchestrator: returns either a match prompt, an auto-created bill, or skip */
export type HandleResult =
  | { kind: "skipped"; reason: string }
  | { kind: "matched"; candidates: any[] }
  | { kind: "created"; bill: { id: string; number: string } };

export async function handlePayment(p: PaymentPayload): Promise<HandleResult> {
  if (!p.vendorId) return { kind: "skipped", reason: "no_vendor" };
  const settings = await getAutoBillSettings(p.companyId);
  if (!settings.enabled) return { kind: "skipped", reason: "disabled" };
  const candidates = await findMatchingBills(p, settings);
  if (candidates.length > 0 && settings.prompt_on_match) {
    return { kind: "matched", candidates };
  }
  const bill = await createAutoBill(p);
  if (!bill) return { kind: "skipped", reason: "create_failed" };
  return { kind: "created", bill };
}
