"use client";

import * as React from "react";
import { DownloadIcon } from "lucide-react";

import { Example } from "@/components/design-system/example";
import { Section } from "@/components/design-system/section";
import { CsvImportReview, FileUpload, downloadText, reviewCsv, type CsvColumn, type CsvReviewResult } from "@/components/medora/file-upload";
import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { toast } from "@/components/ui/toast";

const CUSTOMER_COLUMNS: CsvColumn[] = [
  { key: "name", header: "Name", required: true },
  {
    key: "phone",
    header: "Phone",
    required: true,
    validate: (v) => (/^(\+?254|0)[17]\d{8}$/.test(v.replace(/\s/g, "")) ? undefined : "Use a Kenyan mobile number, e.g. 0712 345 678."),
  },
  { key: "email", header: "Email", validate: (v) => (/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v) ? undefined : "This isn't an email address.") },
  {
    key: "creditLimit",
    header: "Credit limit",
    validate: (v) => (/^\d+(\.\d{1,2})?$/.test(v.replace(/,/g, "")) ? undefined : "Enter an amount in shillings without KES, e.g. 5000."),
  },
];

const TEMPLATE = "Name,Phone,Email,Credit limit\nMary Wambui,0712 345 678,mary@example.com,5000\n";

const SAMPLE = [
  "Name,Phone,Email,Credit limit",
  "Mary Wambui,0712 345 678,mary@example.com,5000",
  "John Otieno,0722 111 222,,0",
  '"Kamau, Peter",+254733000111,peter.kamau@example.com,"12,500"',
  "Grace Achieng,0712 345 678,grace@example.com,2000",
  ",0700 000 001,,",
  "Ali Hassan,12345,ali@,KES 3000",
  "Faith Njeri,0110 222 333,faith@example.com,",
].join("\n");

/** Simulated network upload: reports progress, optionally fails once. */
const fakeUpload = (ms: number, fail?: () => boolean) => (_file: File, onProgress: (pct: number) => void) =>
  new Promise<void>((resolve, reject) => {
    let pct = 0;
    const t = setInterval(() => {
      pct = Math.min(100, pct + 10);
      onProgress(pct);
      if (pct >= 60 && fail?.()) {
        clearInterval(t);
        reject(new Error("The upload stopped at 60%. Check the connection and try again."));
      } else if (pct === 100) {
        clearInterval(t);
        resolve();
      }
    }, ms / 10);
  });

function CustomerImport() {
  const [review, setReview] = React.useState<CsvReviewResult | null>(null);
  const [importing, setImporting] = React.useState(false);
  const [imported, setImported] = React.useState<Record<string, string>[] | null>(null);
  const [run, setRun] = React.useState(0);

  const reset = () => {
    setReview(null);
    setImported(null);
    setRun((r) => r + 1);
  };

  if (imported) {
    return (
      <div className="space-y-3">
        <p className="text-sm font-medium">
          {imported.length} customers imported. Rows with problems were not imported; fix them in the error report and import that file.
        </p>
        <Table className="text-sm">
          <TableHeader>
            <TableRow>
              <TableHead>Name</TableHead>
              <TableHead>Phone</TableHead>
              <TableHead>Email</TableHead>
              <TableHead className="text-right">Credit limit</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {imported.map((c) => (
              <TableRow key={c.phone}>
                <TableCell className="font-medium">{c.name}</TableCell>
                <TableCell className="tabular-nums">{c.phone}</TableCell>
                <TableCell>{c.email || "–"}</TableCell>
                <TableCell className="text-right tabular-nums">{c.creditLimit ? Number(c.creditLimit.replace(/,/g, "")).toLocaleString("en-US") : "–"}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
        <Button variant="outline" onClick={reset}>
          Import another file
        </Button>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <FileUpload
        key={run}
        label="Customer list"
        hint="CSV up to 2 MB. Columns: Name, Phone, Email, Credit limit."
        kind="csv"
        accept={[".csv"]}
        maxBytes={2 * 1024 * 1024}
        onTemplate={() => downloadText("customers-template.csv", TEMPLATE)}
        upload={async (file, onProgress) => {
          await fakeUpload(600)(file, onProgress);
          const result = reviewCsv(await file.text(), CUSTOMER_COLUMNS, "phone");
          setReview(result);
          return result.missingHeaders.length ? "columns missing" : `${result.total} rows found`;
        }}
        onRemove={() => setReview(null)}
      />
      {review ? (
        <CsvImportReview
          result={review}
          noun="customers"
          importing={importing}
          onChooseAnother={reset}
          onImport={async () => {
            setImporting(true);
            await new Promise((r) => setTimeout(r, 900));
            setImporting(false);
            setImported(review.valid);
            toast.add({ title: `${review.valid.length} customers imported` });
          }}
        />
      ) : null}
    </div>
  );
}

export function FileUploadSection() {
  const [flaky, setFlaky] = React.useState(true);
  const failNext = React.useRef(true);

  return (
    <Section
      id="file-upload"
      title="File upload and CSV import"
      description="Choose file is the real control; dragging onto the zone is an extra. Type and size are checked before anything uploads, and the message says what to do (an Excel file asks to be saved as CSV). Progress is shown and announced at start, halfway and done. A CSV import is checked row by row before anything is saved: counts, each problem with its row and fix, a downloadable error report, then an import of the valid rows only."
    >
      <Example
        title="Import customers (CSV)"
        description="Download the sample (it has a duplicate phone, a missing name and bad values), then drop or choose it. Try an .xlsx file too."
        bare
      >
        <div className="space-y-3 p-4">
          <Button variant="outline" size="sm" onClick={() => downloadText("customers-sample-with-problems.csv", SAMPLE)}>
            <DownloadIcon data-icon="inline-start" />
            Sample file with problems
          </Button>
          <CustomerImport />
        </div>
      </Example>
      <div className="grid gap-4 md:grid-cols-2">
        <Example title="Product photo" description="Preview when ready, Replace and Remove, or a link instead. JPG, PNG or WebP under 2 MB.">
          <FileUpload
            label="Product photo"
            hint="JPG, PNG or WebP, up to 2 MB. Square photos look best."
            kind="image"
            accept={[".jpg", ".jpeg", ".png", ".webp"]}
            maxBytes={2 * 1024 * 1024}
            allowUrl
            upload={fakeUpload(1200)}
          />
        </Example>
        <Example title="Upload fails, then Retry" description="The first attempt stops at 60%; Retry sends the same file again">
          <div className="space-y-3">
            <label className="flex items-center gap-2 text-sm">
              <Switch
                checked={flaky}
                onCheckedChange={(v) => {
                  setFlaky(v);
                  failNext.current = v;
                }}
              />
              Drop the connection on the next upload
            </label>
            <FileUpload
              label="Prescription scan"
              hint="JPG or PNG, up to 5 MB."
              kind="image"
              accept={[".jpg", ".jpeg", ".png"]}
              maxBytes={5 * 1024 * 1024}
              upload={(file, onProgress) =>
                fakeUpload(1200, () => {
                  if (!failNext.current) return false;
                  failNext.current = false;
                  setFlaky(false);
                  return true;
                })(file, onProgress)
              }
            />
          </div>
        </Example>
        <Example title="Compact" description="Button only, for table toolbars; the file row appears under it">
          <FileUpload label="Stock count sheet" hint="CSV up to 2 MB." kind="csv" accept={[".csv"]} maxBytes={2 * 1024 * 1024} compact upload={fakeUpload(800)} />
        </Example>
        <Example title="Disabled" description="While another import is still running">
          <FileUpload label="Price list" hint="CSV up to 2 MB." kind="csv" accept={[".csv"]} maxBytes={2 * 1024 * 1024} disabled upload={fakeUpload(800)} />
        </Example>
      </div>
    </Section>
  );
}
