"use client";
import { SearchablePicker } from "./searchable-picker";
import { useRef, useState, type FormEvent } from "react";
import { useRouter } from "next/navigation";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Field, SelectField, TextareaField } from "@/components/shared/field";
import {
  isRecord,
  parseFinancialInput,
  unwrap,
  parseFinancialRecord,
  numeric,
  text,
  type FinancialAction,
  type FinancialRecord,
  type FinancialChargepoints,
} from "./contract";
import { money } from "./display";
export type FinancialDialog = {
  action: FinancialAction;
  row?: FinancialRecord;
  seed?: Record<string, unknown>;
};
const numericFields: Record<FinancialAction, [string, string, string?][]> = {
  estimate: [
    ["investment_amount", "Investment amount"],
    ["ownership_percentage", "Ownership (%)"],
    ["estimated_daily_kwh", "Estimated daily energy (kWh)"],
    ["tariff_per_kwh", "Tariff per kWh"],
    ["electricity_cost_per_kwh", "Electricity cost per kWh"],
    ["estimated_sessions_per_day", "Estimated sessions per day"],
    ["platform_fee_percentage", "Platform fee (%)", "0"],
  ],
  "create-investment": [
    ["investment_amount", "Investment amount"],
    ["ownership_percentage", "Ownership (%)"],
    ["target_bep_months", "Target break-even (months)"],
    ["expected_monthly_revenue", "Expected monthly revenue"],
  ],
  "update-investment": [["actual_revenue_to_date", "Actual revenue to date"]],
  "update-settlement": [],
};
const titles = {
  estimate: "Estimate investment",
  "create-investment": "Create investor investment",
  "update-investment": "Update investor investment",
  "update-settlement": "Update payout settlement",
};
export async function financialFetch(
  path: string,
  method = "GET",
  body?: unknown,
): Promise<unknown> {
  const response = await fetch(`/api/financial/${path}`, {
    method,
    cache: "no-store",
    ...(body
      ? {
          headers: { "content-type": "application/json" },
          body: JSON.stringify(body),
        }
      : {}),
  });
  const data: unknown = await response.json();
  if (!response.ok || (isRecord(data) && data.ok === false))
    throw new Error(
      isRecord(data) && typeof data.error === "string"
        ? data.error
        : "The financial request failed. Refresh the records before trying again.",
    );
  return data;
}
export function FinancialFormDialog({
  dialog,
  close,
  createFromEstimate,
  chargepoints,
  investors,
}: {
  investors: FinancialChargepoints;
  chargepoints: FinancialChargepoints;
  dialog: FinancialDialog;
  close: () => void;
  createFromEstimate: (seed: Record<string, unknown>) => void;
}) {
  const { action, row, seed } = dialog;
  const router = useRouter();
  const [busy, setBusy] = useState(false),
    [error, setError] = useState(""),
    [estimate, setEstimate] = useState<FinancialRecord | null>(null);
  const errorRef = useRef<HTMLParagraphElement>(null),
    submitting = useRef(false);
  const creating = action === "create-investment",
    estimating = action === "estimate";
  const [previousInput, setPreviousInput] = useState<Record<
    string,
    unknown
  > | null>(null);
  const initial = previousInput ?? seed ?? row ?? {};
  async function submit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (submitting.current) return;
    setError("");
    const data = new FormData(event.currentTarget);
    const input: Record<string, unknown> = Object.fromEntries(data);
    for (const [key] of numericFields[action])
      input[key] = data.get(key) === "" ? undefined : Number(data.get(key));
    if (action === "update-investment")
      input.active = data.get("active") === "true";
    for (const key of ["started_at", "ended_at", "bep_reached_at", "paid_at"]) {
      const value = data.get(key);
      if (typeof value === "string" && value) input[key] = `${value}:00+07:00`;
      else delete input[key];
    }
    if (creating || action === "update-investment")
      input.meta_data = {
        ...(isRecord(row?.meta_data) ? row.meta_data : {}),
        notes: input.notes ?? "",
      };
    const payload = parseFinancialInput(action, input);
    if (!payload) {
      setError(
        "Check the fields: use valid UUIDs, nonnegative amounts, percentages from 0 to 100, and valid dates. A paid settlement requires a payment reference and paid date.",
      );
      requestAnimationFrame(() => errorRef.current?.focus());
      return;
    }
    setPreviousInput(payload);
    submitting.current = true;
    setBusy(true);
    try {
      const path = estimating
        ? "investment-estimates"
        : creating
          ? "investor-investments"
          : action === "update-investment"
            ? `investor-investments/${row?.id}`
            : `payout-settlements/${row?.id}/status`;
      const result = await financialFetch(
        path,
        estimating || creating ? "POST" : "PATCH",
        payload,
      );
      if (estimating) setEstimate(parseFinancialRecord(unwrap(result)));
      else {
        router.refresh();
        close();
      }
    } catch (err) {
      setError(
        err instanceof Error
          ? err.message
          : "Unable to save. Reload the records to check their current state before retrying.",
      );
      requestAnimationFrame(() => errorRef.current?.focus());
    } finally {
      submitting.current = false;
      setBusy(false);
    }
  }
  function localDate(value: unknown) {
    if (typeof value !== "string" || !Number.isFinite(Date.parse(value)))
      return "";
    return new Date(Date.parse(value) + 7 * 3600000).toISOString().slice(0, 16);
  }
  return (
    <Dialog
      open
      onOpenChange={(open) => {
        if (!open && !busy) close();
      }}
    >
      <DialogContent
        className="max-h-[90dvh] overflow-y-auto sm:max-w-2xl"
        onInteractOutside={(event) => {
          if (busy) event.preventDefault();
        }}
      >
        <DialogHeader>
          <DialogTitle>{titles[action]}</DialogTitle>
          <DialogDescription>
            {estimating
              ? "Model your investment using projected charging activity and costs."
              : action === "update-settlement"
                ? "Record the settlement status and transfer reference. This does not initiate a bank transfer."
                : "Investment records are saved to your organization’s financial service."}
          </DialogDescription>
        </DialogHeader>
        {estimate ? (
          <div className="space-y-5">
            <div className="rounded-xl border bg-primary/5 p-5">
              <p className="text-sm text-muted-foreground">
                Estimated investor income / month
              </p>
              <p className="mt-2 text-3xl font-semibold tabular-nums">
                {money(
                  estimate.estimated_monthly_investor_share,
                  estimate.currency,
                )}
              </p>
              <p className="mt-2 text-sm">
                Break-even in{" "}
                {numeric(estimate.estimated_bep_months)?.toFixed(1) ?? "—"}{" "}
                months
              </p>
            </div>
            <dl className="grid gap-4 sm:grid-cols-2">
              {[
                ["estimated_monthly_gross", "Monthly gross"],
                [
                  "estimated_monthly_electricity_cost",
                  "Monthly electricity cost",
                ],
                ["estimated_monthly_net", "Monthly net revenue"],
                ["investment_amount", "Investment"],
              ].map(([key, label]) => (
                <div key={key}>
                  <dt className="text-sm text-muted-foreground">{label}</dt>
                  <dd className="mt-1 font-semibold">
                    {money(estimate[key], estimate.currency)}
                  </dd>
                </div>
              ))}
            </dl>
            <div className="flex flex-wrap justify-end gap-2">
              <Button variant="outline" onClick={() => setEstimate(null)}>
                Adjust estimate
              </Button>
              <Button
                onClick={() =>
                  createFromEstimate({
                    charge_point_id: estimate.charge_point_id,
                    currency: estimate.currency,
                    investment_amount: estimate.investment_amount,
                    ownership_percentage: estimate.ownership_percentage,
                    target_bep_months: Math.ceil(
                      numeric(estimate.estimated_bep_months) ?? 0,
                    ),
                    expected_monthly_revenue:
                      estimate.estimated_monthly_investor_share,
                  })
                }
              >
                Create investment from estimate
              </Button>
            </div>
          </div>
        ) : (
          <form onSubmit={submit} className="space-y-5">
            {error && (
              <p
                ref={errorRef}
                tabIndex={-1}
                role="alert"
                className="rounded-lg bg-destructive/10 p-3 text-sm text-destructive"
              >
                {error}
              </p>
            )}
            <fieldset disabled={busy} className="grid gap-4 sm:grid-cols-2">
              {(estimating || creating) && (
                <>
                  <SearchablePicker
                    name="charge_point_id"
                    label="Chargepoint"
                    choices={chargepoints}
                    defaultValue={text(initial, "charge_point_id")}
                    disabled={busy}
                    retry={() => router.refresh()}
                  />
                  <Field
                    name="currency"
                    label="Currency"
                    required
                    pattern="[A-Z]{3}"
                    maxLength={3}
                    defaultValue={text(initial, "currency") || "IDR"}
                  />
                </>
              )}
              {creating && (
                <SearchablePicker
                  name="investor_user_id"
                  label="Investor"
                  choices={investors}
                  defaultValue={text(initial, "investor_user_id")}
                  disabled={busy}
                  retry={() => router.refresh()}
                />
              )}
              {numericFields[action].map(([key, label, fallback]) => (
                <Field
                  key={key}
                  name={key}
                  label={label}
                  type="number"
                  min={key === "investment_amount" ? 0.01 : 0}
                  max={key.endsWith("percentage") ? 100 : undefined}
                  step="any"
                  required
                  defaultValue={
                    typeof initial[key] === "number" ? initial[key] : fallback
                  }
                />
              ))}
              {creating && (
                <Field
                  name="started_at"
                  label="Started at (Jakarta)"
                  type="datetime-local"
                  required
                />
              )}
              {action === "update-investment" && (
                <>
                  <SelectField
                    name="active"
                    label="Investment status"
                    defaultValue={String(row?.active === true)}
                    options={[
                      { value: "true", label: "Active" },
                      { value: "false", label: "Inactive" },
                    ]}
                  />
                  <Field
                    name="ended_at"
                    label="Ended at (Jakarta, optional)"
                    type="datetime-local"
                    defaultValue={localDate(row?.ended_at)}
                  />
                  <Field
                    name="bep_reached_at"
                    label="Break-even reached (Jakarta, optional)"
                    type="datetime-local"
                    defaultValue={localDate(row?.bep_reached_at)}
                  />
                </>
              )}
              {action === "update-settlement" && (
                <>
                  <Field
                    name="status"
                    label="Settlement status"
                    required
                    defaultValue={row ? text(row, "status") : ""}
                    placeholder="e.g. paid"
                    pattern="[a-z_]+"
                  />
                  <Field
                    name="payment_reference"
                    label="Payment reference"
                    maxLength={255}
                    defaultValue={row ? text(row, "payment_reference") : ""}
                  />
                  <Field
                    name="paid_at"
                    label="Paid at (Jakarta)"
                    type="datetime-local"
                    defaultValue={localDate(row?.paid_at)}
                  />
                </>
              )}
              {!estimating && (
                <div className="sm:col-span-2">
                  <TextareaField
                    name="notes"
                    label="Notes"
                    maxLength={2000}
                    defaultValue={
                      row && isRecord(row.meta_data)
                        ? text(row.meta_data, "notes")
                        : row
                          ? text(row, "notes")
                          : ""
                    }
                  />
                </div>
              )}
            </fieldset>
            <div className="flex justify-end gap-2">
              <Button
                type="button"
                variant="outline"
                disabled={busy}
                onClick={close}
              >
                Cancel
              </Button>
              <Button
                disabled={
                  busy ||
                  (creating &&
                    (!!investors.error || investors.options.length === 0)) ||
                  ((estimating || creating) &&
                    (!!chargepoints.error || chargepoints.options.length === 0))
                }
                type="submit"
              >
                {busy
                  ? "Saving…"
                  : estimating
                    ? "Calculate estimate"
                    : "Save changes"}
              </Button>
            </div>
          </form>
        )}
      </DialogContent>
    </Dialog>
  );
}
