import type { CategoryType, FinancialPhase } from "@prisma/client";
import { createExpenseAction, deleteExpenseAction, updateExpenseAction } from "@/app/actions";
import { AutoMoneyFields } from "@/components/AutoMoneyFields";
import { ChartPanel, DistributionPieChart, SimpleLineChart } from "@/components/Charts";
import { ConfirmSubmitButton } from "@/components/ConfirmSubmitButton";
import { DeleteButton } from "@/components/DeleteButton";
import { EmptyState } from "@/components/EmptyState";
import { ExpenseDetailPanel } from "@/components/ExpenseDetailPanel";
import { ExportOptions } from "@/components/ExportOptions";
import { FundingFields } from "@/components/FundingFields";
import { LaborFields } from "@/components/LaborFields";
import { PageHeader } from "@/components/PageHeader";
import { PaginationControls } from "@/components/PaginationControls";
import { ReceiptUploader } from "@/components/ReceiptUploader";
import { ReceiptFilesButton } from "@/components/ReceiptFilesViewer";
import { SelectionToolbar } from "@/components/SelectionToolbar";
import { StatusMessage } from "@/components/StatusMessage";
import { SummaryCard } from "@/components/SummaryCard";
import { TransactionTableRow } from "@/components/TransactionTableRow";
import { AppShell } from "@/components/AppShell";
import { expenseByCategory, expenseByMonth } from "@/lib/chartData";
import { expenseExportParams, filterExpenses, parseExpenseFilters, summarizeExpenses, type ExpenseRecord } from "@/lib/expenseFilters";
import { financialPhaseLabels } from "@/lib/finance";
import { currency, dateInput, shortDate } from "@/lib/format";
import { laborPaymentBasisOptions, laborPaymentStatusOptions, workerSummaryMap } from "@/lib/labor";
import { paginateItems, paginationFromParams } from "@/lib/pagination";
import { permissionForCostPhase } from "@/lib/permissions";
import { getSelectedProject } from "@/lib/projects";

const splitMethods = [
  ["EQUAL", "Equal split"],
  ["OWNERSHIP", "Ownership percentage"],
  ["CUSTOM_PERCENTAGE", "Custom percentage"],
  ["CUSTOM_AMOUNT", "Custom amount"],
  ["PERSONAL", "Personal expense"]
] as const;

type CostRecordsPageProps = {
  searchParams?: Promise<Record<string, string | string[] | undefined>>;
  title: string;
  description: string;
  addTitle: string;
  listTitle: string;
  returnTo: string;
  allowedPhases: FinancialPhase[];
  categoryTypes: CategoryType[];
  discountLabel?: string;
};

function belongsOnPage(expense: ExpenseRecord, allowedPhases: FinancialPhase[], categoryTypes: CategoryType[]) {
  if (allowedPhases.includes(expense.phase)) return true;
  return expense.phase === "OTHER" && Boolean(expense.category?.type && categoryTypes.includes(expense.category.type));
}

function PhaseField({
  allowedPhases,
  defaultPhase
}: {
  allowedPhases: FinancialPhase[];
  defaultPhase?: FinancialPhase;
}) {
  const selected = defaultPhase && allowedPhases.includes(defaultPhase) ? defaultPhase : allowedPhases[0];
  if (allowedPhases.length === 1) {
    return <input type="hidden" name="phase" value={selected} />;
  }

  return (
    <label className="grid gap-2">
      <span className="label">Financial phase</span>
      <select className="field" name="phase" defaultValue={selected}>
        {allowedPhases.map((phase) => (
          <option key={phase} value={phase}>{financialPhaseLabels[phase]}</option>
        ))}
      </select>
    </label>
  );
}

export async function CostRecordsPage({
  searchParams,
  title,
  description,
  addTitle,
  listTitle,
  returnTo,
  allowedPhases,
  categoryTypes,
  discountLabel = "Discount / Credit"
}: CostRecordsPageProps) {
  const params = (await searchParams) ?? {};
  const filters = parseExpenseFilters(params);
  const costPermissions = permissionForCostPhase(returnTo);
  const { user, projects, project, permissions, projectRole } = await getSelectedProject(filters.projectId, costPermissions.view);
  const canCreate = Boolean(permissions?.[costPermissions.create]);
  const canEdit = Boolean(permissions?.[costPermissions.edit]);
  const canDelete = Boolean(permissions?.[costPermissions.delete] || permissions?.[costPermissions.archive]);
  const canExport = Boolean(permissions?.["expenses.export"] || permissions?.["reports.export"]);

  if (!project) {
    return (
      <AppShell projects={projects} username={user.name ?? user.username ?? user.email} role={projectRole ?? user.role} permissions={permissions}>
        <EmptyState title="Create a project before tracking costs." href="/projects" actionLabel="Create project" />
      </AppShell>
    );
  }

  const pageExpenses = project.expenses.filter((expense) => belongsOnPage(expense, allowedPhases, categoryTypes));
  const filteredExpenses = filterExpenses(pageExpenses, filters);
  const pagination = paginationFromParams(params, filteredExpenses.length);
  const pagedExpenses = paginateItems(filteredExpenses, pagination);
  const summary = summarizeExpenses(filteredExpenses);
  const categories = project.categories.filter((category) => categoryTypes.includes(category.type));
  const exportParams = expenseExportParams(project.id, filters);
  exportParams.set("phase", allowedPhases.join(","));
  const monthlyData = expenseByMonth(filteredExpenses);
  const categoryData = expenseByCategory(filteredExpenses);
  const partnerOptions = project.partners.map((partner) => ({ id: partner.id, name: partner.partner.name }));
  const laborSummaries = workerSummaryMap(project);
  const workerOptions = project.workers.map((worker) => ({
    id: worker.id,
    name: worker.name,
    role: worker.role,
    isActive: worker.isActive,
    defaultDailyRate: worker.defaultDailyRate ? Number(worker.defaultDailyRate) : null,
    defaultHourlyRate: worker.defaultHourlyRate ? Number(worker.defaultHourlyRate) : null,
    summary: laborSummaries[worker.id]
  }));
  const accountOptions = project.projectAccounts.map((account) => ({
    id: account.id,
    accountName: account.accountName,
    active: account.active
  }));

  return (
    <AppShell projects={projects} selectedProjectId={project.id} username={user.name ?? user.username ?? user.email} role={projectRole ?? user.role} permissions={permissions}>
      <PageHeader
        title={title}
        description={description}
        actions={
          <>
            {canExport ? <ExportOptions baseUrl={`/api/exports/expenses?${exportParams.toString()}`} reportTitle={`${title} Export`} /> : null}
          </>
        }
      />
      <StatusMessage updated={params.updated} deleted={params.deleted} error={params.error} />

      <section className="grid gap-6 xl:grid-cols-[0.9fr_1.1fr]">
        {canCreate ? (
          <details className="action-modal justify-self-start">
            <summary>{addTitle}</summary>
            <form action={createExpenseAction} className="grid gap-4">
              <div>
                <p className="text-xs font-semibold uppercase tracking-normal text-blue-700">New record</p>
                <h3 className="mt-1 text-lg font-semibold text-ink">{addTitle}</h3>
              </div>
            <input type="hidden" name="projectId" value={project.id} />
            <input type="hidden" name="recordType" value="EXPENSE" />
            <input type="hidden" name="returnTo" value={returnTo} />
            <PhaseField allowedPhases={allowedPhases} />
            <LaborFields workers={workerOptions} />
            <div className="grid gap-4 md:grid-cols-2">
              <label className="grid gap-2">
                <span className="label">Date</span>
                <input className="field" name="date" type="date" defaultValue={new Date().toISOString().slice(0, 10)} required />
              </label>
            </div>
            <FundingFields partners={partnerOptions} accounts={accountOptions} />
            <div className="grid gap-4 md:grid-cols-2">
              <label className="grid gap-2">
                <span className="label">Category</span>
                <select className="field" name="categoryId">
                  <option value="">Uncategorized</option>
                  {categories.map((category) => (
                    <option key={category.id} value={category.id}>{category.name}</option>
                  ))}
                </select>
              </label>
              <label className="grid gap-2">
                <span className="label">Vendor / store</span>
                <input className="field" name="vendor" />
              </label>
            </div>
            <label className="grid gap-2">
              <span className="label">Description</span>
              <input className="field" name="description" />
            </label>
            <AutoMoneyFields discountLabel={discountLabel} />
            <label className="grid gap-2">
              <span className="label">Split method</span>
              <select className="field" name="splitMethod" defaultValue="EQUAL">
                {splitMethods.map(([value, label]) => (
                  <option key={value} value={value}>{label}</option>
                ))}
              </select>
            </label>
            <div className="rounded-md border border-line p-3">
              <p className="label mb-3">Split between</p>
              <div className="grid gap-3">
                {project.partners.map((partner) => (
                  <div key={partner.id} className="grid gap-2 rounded-md bg-slate-50 p-3 md:grid-cols-[1fr_120px_120px] md:items-center">
                    <label className="flex items-center gap-2 text-sm font-medium text-slate-700">
                      <input className="h-4 w-4 rounded border-line" name="splitPartnerIds" value={partner.id} type="checkbox" defaultChecked={partner.active} />
                      {partner.partner.name}
                    </label>
                    <input className="field" name={`customPercentage:${partner.id}`} type="number" step="0.01" min="0" max="100" placeholder="%" />
                    <input className="field" name={`customAmount:${partner.id}`} type="number" step="0.01" min="0" placeholder="$" />
                  </div>
                ))}
              </div>
            </div>
            <label className="grid gap-2">
              <span className="label">Personal expense partner</span>
              <select className="field" name="personalPartnerId">
                {project.partners.map((partner) => (
                  <option key={partner.id} value={partner.id}>{partner.partner.name}</option>
                ))}
              </select>
            </label>
            <div className="grid gap-4 md:grid-cols-2">
              <ReceiptUploader multiple />
              <label className="grid gap-2">
                <span className="label">Notes</span>
                <input className="field" name="notes" />
              </label>
            </div>
            <ConfirmSubmitButton title="Review before saving" message="Save this cost with the calculated final cost and funding details?" confirmLabel="Confirm Save">
              Save cost
            </ConfirmSubmitButton>
            </form>
          </details>
        ) : null}

        <div className="grid gap-4">
          <form className="panel grid gap-3 p-4 md:grid-cols-2" action={returnTo}>
            <input type="hidden" name="projectId" value={project.id} />
            <input className="field" name="search" placeholder="Description or notes" defaultValue={filters.search} />
            <input className="field" name="vendor" placeholder="Vendor/store" defaultValue={filters.vendor} />
            <select className="field" name="category" defaultValue={filters.category}>
              <option value="">All categories</option>
              {categories.map((category) => (
                <option key={category.id} value={category.id}>{category.name}</option>
              ))}
            </select>
            <select className="field" name="transactionKind" defaultValue={filters.transactionKind}>
              <option value="">All transaction types</option>
              <option value="STANDARD">Standard Expense</option>
              <option value="LABOR_COST">Labor Cost / Worker Payment</option>
            </select>
            <select className="field" name="workerId" defaultValue={filters.workerId}>
              <option value="">All workers</option>
              {project.workers.map((worker) => (
                <option key={worker.id} value={worker.id}>{worker.name}</option>
              ))}
            </select>
            <select className="field" name="paidBy" defaultValue={filters.paidBy}>
              <option value="">Any handled-by partner</option>
              {project.partners.map((partner) => (
                <option key={partner.id} value={partner.id}>{partner.partner.name}</option>
              ))}
            </select>
            <input className="field" name="from" type="date" defaultValue={filters.from} title="From date" />
            <input className="field" name="to" type="date" defaultValue={filters.to} title="To date" />
            <select className="field" name="laborPaymentBasis" defaultValue={filters.laborPaymentBasis}>
              <option value="">All labor payment bases</option>
              {laborPaymentBasisOptions.map(([value, label]) => (
                <option key={value} value={value}>{label}</option>
              ))}
            </select>
            <select className="field" name="laborPaymentStatus" defaultValue={filters.laborPaymentStatus}>
              <option value="">All labor statuses</option>
              {laborPaymentStatusOptions.map(([value, label]) => (
                <option key={value} value={value}>{label}</option>
              ))}
            </select>
            <button className="btn-secondary md:col-span-2">Apply filters</button>
          </form>

          <section className="grid gap-4 md:grid-cols-2">
            <SummaryCard label="Final cost" value={summary.totalFinalCost} />
            <SummaryCard label="Records" value={String(summary.count)} />
            <SummaryCard label="Discounts/credits" value={summary.totalDiscount} />
            <SummaryCard label="Top category" value={summary.topCategory?.name ?? "-"} detail={summary.topCategory ? currency(summary.topCategory.amount) : undefined} />
          </section>
        </div>
      </section>

      <section className="mt-6 grid gap-6 xl:grid-cols-2">
        <ChartPanel title={`${title} by Month`}>
          <SimpleLineChart data={monthlyData} dataKey="expenses" />
        </ChartPanel>
        <ChartPanel title={`${title} by Category`}>
          <DistributionPieChart data={categoryData} />
        </ChartPanel>
      </section>

      <section className="panel mt-6 overflow-hidden">
        <div className="border-b border-line px-4 py-3">
          <h3 className="font-semibold text-ink">{listTitle}</h3>
        </div>
        <div className="overflow-x-auto">
          <SelectionToolbar totalRecords={filteredExpenses.length}>
          <table className="w-full min-w-[980px]">
            <thead className="table-head">
              <tr>
                <th className="px-3 py-2">Select</th>
                <th className="px-3 py-2">Details</th>
                <th className="px-3 py-2">Date</th>
                <th className="px-3 py-2">Vendor / Name</th>
                <th className="px-3 py-2">Category</th>
                <th className="px-3 py-2">Paid By</th>
                <th className="px-3 py-2">Final Price</th>
                <th className="px-3 py-2">Project</th>
                {canEdit || canDelete || canExport ? <th className="px-3 py-2">Actions</th> : null}
              </tr>
            </thead>
            <tbody>
              {pagedExpenses.map((expense) => {
                const personalPartnerId = expense.shares[0]?.projectPartnerId ?? expense.paidById ?? "";
                return (
                  <TransactionTableRow
                    key={expense.id}
                    id={expense.id}
                    selectLabel={`Select ${expense.vendor ?? expense.description ?? "cost"}`}
                    date={shortDate(expense.date)}
                    description={expense.vendor ?? expense.description ?? expense.worker?.name ?? "-"}
                    category={expense.transactionKind === "LABOR_COST" ? "Labor Cost" : expense.category?.name ?? "-"}
                    paidBy={expense.paidBy?.partner.name ?? "-"}
                    amount={currency(Number(expense.finalCost))}
                    project={project.name}
                    detail={<ExpenseDetailPanel expense={expense} workerSummary={expense.workerId ? laborSummaries[expense.workerId] : null} />}
                    actionColumn={canEdit || canDelete || canExport}
                    actions={(
                        <div className="flex flex-wrap gap-2">
                          {canExport ? (
                            <a className="btn-secondary px-2 py-1 text-xs" href={`/api/exports/expenses?projectId=${project.id}&scope=selected&selectedIds=${expense.id}&format=xlsx&reportTitle=Single%20Cost`}>
                              Export
                            </a>
                          ) : null}
                          <ReceiptFilesButton files={expense.receiptFiles} legacyUrl={expense.receiptUrl} emptyLabel="No Receipt" compact />
                          {canEdit ? <details className="action-modal">
                            <summary>Edit</summary>
                            <form action={updateExpenseAction} className="grid gap-3">
                              <div>
                                <p className="text-xs font-semibold uppercase tracking-normal text-blue-700">Edit record</p>
                                <h3 className="mt-1 text-lg font-semibold text-ink">{expense.vendor ?? expense.description ?? "Cost"}</h3>
                              </div>
                              <input type="hidden" name="projectId" value={project.id} />
                              <input type="hidden" name="expenseId" value={expense.id} />
                              <input type="hidden" name="recordType" value="EXPENSE" />
                              <input type="hidden" name="returnTo" value={returnTo} />
                              <PhaseField allowedPhases={allowedPhases} defaultPhase={expense.phase} />
                              <LaborFields
                                workers={workerOptions}
                                defaultTransactionKind={expense.transactionKind}
                                defaultWorkerId={expense.workerId}
                                defaultWorkStartDate={dateInput(expense.workStartDate)}
                                defaultWorkEndDate={dateInput(expense.workEndDate)}
                                defaultActualPaidWorkDays={expense.actualPaidWorkDays ? Number(expense.actualPaidWorkDays) : ""}
                                defaultLaborPaymentBasis={expense.laborPaymentBasis}
                                defaultLaborPaymentStatus={expense.laborPaymentStatus}
                                defaultWorkDescription={expense.workDescription}
                                defaultWorkArea={expense.workArea}
                              />
                              <input className="field" name="date" type="date" defaultValue={dateInput(expense.date)} required />
                              <FundingFields
                                partners={partnerOptions}
                                accounts={accountOptions}
                                defaultPaidById={expense.paidById}
                                defaultFundingSourceType={expense.fundingSourceType}
                                defaultFundingPartnerId={expense.fundingPartnerId}
                                defaultProjectAccountId={expense.projectAccountId}
                                defaultCreatesContributionCredit={expense.createsContributionCredit}
                                defaultContributionCreditPartnerId={expense.contributionCreditPartnerId}
                                defaultContributionCreditAmount={expense.contributionCreditAmount ? Number(expense.contributionCreditAmount) : ""}
                                defaultPaymentMemo={expense.paymentMemo}
                              />
                              <select className="field" name="categoryId" defaultValue={expense.categoryId ?? ""}>
                                <option value="">Uncategorized</option>
                                {categories.map((category) => (
                                  <option key={category.id} value={category.id}>{category.name}</option>
                                ))}
                              </select>
                              <input className="field" name="vendor" defaultValue={expense.vendor ?? ""} placeholder="Vendor" />
                              <input className="field" name="description" defaultValue={expense.description ?? ""} placeholder="Description" />
                              <AutoMoneyFields defaultAmount={Number(expense.amount)} defaultDiscount={Number(expense.discount)} discountLabel={discountLabel} className="grid gap-3 md:grid-cols-3" />
                              <select className="field" name="splitMethod" defaultValue={expense.splitMethod}>
                                {splitMethods.map(([value, label]) => (
                                  <option key={value} value={value}>{label}</option>
                                ))}
                              </select>
                              <div className="rounded-md border border-line p-3">
                                <p className="label mb-3">Split details</p>
                                <div className="grid gap-3">
                                  {project.partners.map((partner) => {
                                    const share = expense.shares.find((item) => item.projectPartnerId === partner.id);
                                    return (
                                      <div key={partner.id} className="grid gap-2 rounded-md bg-slate-50 p-3 md:grid-cols-[1fr_120px_120px] md:items-center">
                                        <label className="flex items-center gap-2 text-sm font-medium text-slate-700">
                                          <input className="h-4 w-4 rounded border-line" name="splitPartnerIds" value={partner.id} type="checkbox" defaultChecked={Boolean(share)} />
                                          {partner.partner.name}
                                        </label>
                                        <input className="field" name={`customPercentage:${partner.id}`} type="number" step="0.01" min="0" max="100" defaultValue={share?.sharePercentage ? Number(share.sharePercentage) : ""} placeholder="%" />
                                        <input className="field" name={`customAmount:${partner.id}`} type="number" step="0.01" min="0" defaultValue={share ? Number(share.shareAmount) : ""} placeholder="$" />
                                      </div>
                                    );
                                  })}
                                </div>
                              </div>
                              <select className="field" name="personalPartnerId" defaultValue={personalPartnerId}>
                                {project.partners.map((partner) => (
                                  <option key={partner.id} value={partner.id}>{partner.partner.name}</option>
                                ))}
                              </select>
                              <ReceiptUploader
                                multiple
                                existingUrl={expense.receiptUrl}
                                existingFileName={expense.receiptFiles[0]?.fileName}
                                existingMimeType={expense.receiptFiles[0]?.mimeType}
                                allowDelete
                              />
                              <textarea className="field min-h-20" name="notes" defaultValue={expense.notes ?? ""} />
                              <ConfirmSubmitButton title="Review changes" message="Update this cost and recalculate final cost/credit amount?" confirmLabel="Confirm Update">
                                Update cost
                              </ConfirmSubmitButton>
                            </form>
                          </details> : null}
                          {canDelete ? <form action={deleteExpenseAction}>
                            <input type="hidden" name="projectId" value={project.id} />
                            <input type="hidden" name="expenseId" value={expense.id} />
                            <input type="hidden" name="returnTo" value={returnTo} />
                            <DeleteButton label="Delete cost" message="Delete this cost record?" />
                          </form> : null}
                        </div>
                    )}
                  />
                );
              })}
            </tbody>
          </table>
          </SelectionToolbar>
          <PaginationControls pagination={pagination} pathname={returnTo} params={params} />
          {pagedExpenses.length === 0 ? (
            <div className="p-6 text-sm text-slate-600">No records match this page and filter.</div>
          ) : null}
        </div>
      </section>
    </AppShell>
  );
}
