/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * Offline (counter) sales import.
 *
 * A sale rung up at the till never passes through the app, so nothing deducts
 * its stock. This is how that stock gets deducted: download a spreadsheet
 * pre-filled with the catalogue, type sold quantities into it, upload it back.
 * Imported sales become real orders, so they reduce stock through the same path
 * an app order uses and show up in revenue reporting.
 *
 * ONE file covers EVERY branch. There is no store picker: each row of the sheet
 * carries its own tenantid and locationid, and that row's locationid decides
 * which branch the sale comes out of. A merchant with six outlets fills in rows
 * for all six and uploads once. Nothing here has to know or choose a store.
 *
 * The template must be downloaded rather than hand-written because `productid`
 * is the only usable key for a product — SKUs are not unique in this catalogue
 * (6,245 products share 93 sku values) and names are not unique either. The
 * download fills productid and locationid in so nobody has to know them.
 *
 * Used by both surfaces. The admin console passes no locationId, so the file
 * routes itself. The store user's page passes theirs, which pins the upload to
 * their branch and rejects rows for any other — enforced again server-side.
 */

import { useCallback, useMemo, useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
  AlertTriangle,
  CheckCircle2,
  Download,
  FileSpreadsheet,
  Loader2,
  RotateCcw,
  Store,
  Upload,
  X,
  XCircle,
} from 'lucide-react';
import {
  getSaleTemplate,
  uploadOfflineSales,
  type OfflineSalesUploadResponse,
} from '../services/fiestaApi';
import {
  downloadSaleTemplate,
  parseSalesWorkbook,
  summarise,
  toBills,
  type ParsedSheet,
} from '../services/offlineSalesSheet';

interface OfflineSalesUploadProps {
  tenantId: number;
  /**
   * Pins the upload to a single branch. Passed by the store user's page so they
   * can only ever import for their own store. Omitted by the admin console, so
   * the workbook spans every branch and each row routes itself.
   */
  locationId?: number;
  /** Shown in the header when the upload is pinned to one store. */
  storeName?: string;
  userId?: number;
  onClose: () => void;
}

const money = (n: number) =>
  `₹${n.toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

export default function OfflineSalesUpload({
  tenantId,
  locationId,
  storeName,
  userId,
  onClose,
}: OfflineSalesUploadProps) {
  const queryClient = useQueryClient();
  const fileInputRef = useRef<HTMLInputElement>(null);

  const [parsed, setParsed] = useState<ParsedSheet | null>(null);
  const [fileName, setFileName] = useState('');
  const [dragging, setDragging] = useState(false);
  const [result, setResult] = useState<OfflineSalesUploadResponse | null>(null);
  const [uploadError, setUploadError] = useState('');

  const pinned = (locationId ?? 0) > 0;

  const templateQuery = useQuery({
    queryKey: ['saleTemplate', tenantId, locationId ?? 0],
    queryFn: () => getSaleTemplate({ tenantid: tenantId, locationid: locationId ?? 0 }),
    enabled: tenantId > 0,
    // Always refetched on open: a template is only useful if its stock figures
    // and product list match the outlets right now.
    staleTime: 0,
  });

  const template = templateQuery.data;
  const summary = useMemo(() => (parsed ? summarise(parsed.rows) : null), [parsed]);
  const blocked = Boolean(parsed && (parsed.fatal.length > 0 || (summary?.errors ?? 0) > 0));

  const uploadMutation = useMutation({
    mutationFn: async () => {
      if (!parsed) throw new Error('No file loaded.');
      return uploadOfflineSales({
        tenantid: tenantId,
        // Sent only when pinned. Left at 0, the backend routes each bill by the
        // locationid the sheet gave it.
        locationid: locationId ?? 0,
        userid: userId,
        bills: toBills(parsed.rows),
      });
    },
    onSuccess: (res) => {
      setResult(res);
      setUploadError('');
      // Stock has moved at potentially several branches, so every view reading
      // it is now stale. Invalidating broadly is deliberate — a partially
      // refreshed inventory screen after an import is worse than a few extra
      // refetches.
      queryClient.invalidateQueries();
    },
    onError: (err: Error) => setUploadError(err.message),
  });

  const loadFile = useCallback(
    async (file: File) => {
      setResult(null);
      setUploadError('');
      setFileName(file.name);
      try {
        const buffer = await file.arrayBuffer();
        setParsed(
          parseSalesWorkbook(buffer, {
            tenantid: tenantId,
            locationid: locationId,
            allowedLocationIds: template?.locations.map((l) => l.locationid),
          }),
        );
      } catch {
        setParsed({
          tenantid: null,
          rows: [],
          skipped: 0,
          fatal: ['That file could not be read. Upload the .xlsx template you downloaded.'],
        });
      }
    },
    [tenantId, locationId, template],
  );

  const reset = () => {
    setParsed(null);
    setFileName('');
    setResult(null);
    setUploadError('');
    if (fileInputRef.current) fileInputRef.current.value = '';
  };

  const storeCount = template?.locations.length ?? 0;
  const scopeLabel = pinned
    ? storeName || template?.locations[0]?.locationname || `Outlet ${locationId}`
    : storeCount === 1
      ? template?.locations[0]?.locationname || 'your store'
      : `all ${storeCount} stores`;

  return (
    <div className="fixed inset-0 z-[200] flex items-center justify-center p-4">
      <div className="absolute inset-0 bg-slate-900/50" onClick={onClose} />

      <div className="relative z-10 flex max-h-[92vh] w-full max-w-6xl flex-col overflow-hidden rounded-xl bg-white shadow-2xl">
        <div className="flex shrink-0 items-center justify-between bg-[#662582] px-6 py-4">
          <div className="flex items-center gap-3">
            <FileSpreadsheet size={20} className="text-white/90" />
            <div>
              <h2 className="text-lg font-bold tracking-tight text-white">Offline Sales Upload</h2>
              <p className="text-xs text-white/70">
                Counter sales for <span className="font-semibold text-white/90">{scopeLabel}</span>
              </p>
            </div>
          </div>
          <button
            onClick={onClose}
            className="flex h-8 w-8 items-center justify-center rounded-full text-white/80 transition-colors hover:bg-white/10 hover:text-white"
            aria-label="Close"
          >
            <X size={20} />
          </button>
        </div>

        <div className="flex-1 overflow-y-auto p-6">
          {result ? (
            <ResultPanel result={result} onAnother={reset} onClose={onClose} />
          ) : (
            <>
              {/* Step 1 — the template. Presented first and prominently because
                  uploading anything else will not work. */}
              <section className="mb-6 rounded-lg border border-slate-200 bg-slate-50 p-5">
                <div className="flex flex-wrap items-center justify-between gap-4">
                  <div>
                    <h3 className="flex items-center gap-2 text-sm font-bold text-slate-800">
                      <span className="flex h-5 w-5 items-center justify-center rounded-full bg-[#662582] text-[11px] font-bold text-white">
                        1
                      </span>
                      Download the template
                    </h3>
                    <p className="mt-1.5 text-xs leading-relaxed text-slate-600">
                      {templateQuery.isLoading
                        ? 'Loading your catalogue…'
                        : templateQuery.isError
                          ? 'Could not load your catalogue.'
                          : pinned || storeCount <= 1
                            ? `${template?.products.length ?? 0} products stocked. Fill in the qtysold column and upload the file back.`
                            : `${template?.products.length ?? 0} rows covering all ${storeCount} stores. Every row already says which store it belongs to — fill in qtysold wherever you sold something and upload the one file.`}
                    </p>
                  </div>
                  <button
                    onClick={() => template && downloadSaleTemplate(template)}
                    disabled={!template || templateQuery.isLoading}
                    className="flex items-center gap-2 rounded-lg bg-[#662582] px-4 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-[#551f6d] disabled:cursor-not-allowed disabled:opacity-50"
                  >
                    {templateQuery.isLoading ? (
                      <Loader2 size={16} className="animate-spin" />
                    ) : (
                      <Download size={16} />
                    )}
                    Download Template
                  </button>
                </div>

                {/* What the one file covers. Shown so it is obvious up front
                    that no store has to be chosen anywhere. */}
                {!pinned && storeCount > 1 && (
                  <div className="mt-4 flex flex-wrap gap-2 border-t border-slate-200 pt-3">
                    {template?.locations.map((l) => (
                      <span
                        key={l.locationid}
                        className="flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-2.5 py-1 text-[11px] font-medium text-slate-700"
                      >
                        <Store size={11} className="text-[#662582]" />
                        {l.locationname}
                        <span className="text-slate-400">#{l.locationid}</span>
                        <span className="text-slate-400">· {l.productcount}</span>
                      </span>
                    ))}
                  </div>
                )}

                {templateQuery.isError && (
                  <p className="mt-3 rounded border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700">
                    {(templateQuery.error as Error).message}
                  </p>
                )}
              </section>

              {/* Step 2 — the file. */}
              <section className="mb-6">
                <h3 className="mb-3 flex items-center gap-2 text-sm font-bold text-slate-800">
                  <span className="flex h-5 w-5 items-center justify-center rounded-full bg-[#662582] text-[11px] font-bold text-white">
                    2
                  </span>
                  Upload the filled-in file
                </h3>

                <div
                  onDragOver={(e) => {
                    e.preventDefault();
                    setDragging(true);
                  }}
                  onDragLeave={() => setDragging(false)}
                  onDrop={(e) => {
                    e.preventDefault();
                    setDragging(false);
                    const file = e.dataTransfer.files?.[0];
                    if (file) void loadFile(file);
                  }}
                  onClick={() => fileInputRef.current?.click()}
                  className={`cursor-pointer rounded-lg border-2 border-dashed p-8 text-center transition-colors ${
                    dragging
                      ? 'border-[#662582] bg-purple-50'
                      : 'border-slate-300 bg-white hover:border-slate-400 hover:bg-slate-50'
                  }`}
                >
                  <Upload size={26} className="mx-auto mb-2 text-slate-400" />
                  <p className="text-sm font-medium text-slate-700">
                    {fileName || 'Drop the .xlsx file here, or click to choose'}
                  </p>
                  <p className="mt-1 text-xs text-slate-500">Only the template downloaded above will import correctly.</p>
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept=".xlsx,.xls,.csv"
                    className="hidden"
                    onChange={(e) => {
                      const file = e.target.files?.[0];
                      if (file) void loadFile(file);
                    }}
                  />
                </div>
              </section>

              {/* Step 3 — the preview. Every problem is shown at once, against
                  the operator's own row numbers, so the file can be fixed in one
                  pass rather than one rejection at a time. */}
              {parsed && (
                <section>
                  <h3 className="mb-3 flex items-center gap-2 text-sm font-bold text-slate-800">
                    <span className="flex h-5 w-5 items-center justify-center rounded-full bg-[#662582] text-[11px] font-bold text-white">
                      3
                    </span>
                    Check and confirm
                  </h3>

                  {parsed.fatal.length > 0 && (
                    <div className="mb-4 rounded-lg border border-red-200 bg-red-50 p-4">
                      {parsed.fatal.map((f, i) => (
                        <p key={i} className="flex items-start gap-2 text-sm text-red-800">
                          <XCircle size={16} className="mt-0.5 shrink-0" />
                          {f}
                        </p>
                      ))}
                    </div>
                  )}

                  {summary && parsed.rows.length > 0 && (
                    <>
                      <div className="mb-4 grid grid-cols-2 gap-3 sm:grid-cols-6">
                        <Stat label="Stores" value={String(summary.stores)} />
                        <Stat label="Bills" value={String(summary.bills)} />
                        <Stat label="Lines" value={String(summary.lines)} />
                        <Stat label="Units" value={String(summary.units)} />
                        <Stat label="Amount" value={money(summary.amount)} />
                        <Stat
                          label="Problems"
                          value={String(summary.errors)}
                          tone={summary.errors > 0 ? 'bad' : 'good'}
                        />
                      </div>

                      {/* Per-store totals. With one file covering the whole
                          business, the single figure above is not enough to
                          sanity-check what is about to be deducted where. */}
                      {summary.stores > 1 && (
                        <div className="mb-4 overflow-hidden rounded-lg border border-slate-200">
                          <table className="w-full text-left text-xs">
                            <thead className="bg-slate-100 text-[11px] uppercase tracking-wide text-slate-600">
                              <tr>
                                <th className="px-3 py-2 font-semibold">Store</th>
                                <th className="px-3 py-2 text-right font-semibold">Lines</th>
                                <th className="px-3 py-2 text-right font-semibold">Units</th>
                                <th className="px-3 py-2 text-right font-semibold">Amount</th>
                                <th className="px-3 py-2 text-right font-semibold">Problems</th>
                              </tr>
                            </thead>
                            <tbody className="divide-y divide-slate-100">
                              {summary.byStore.map((s) => (
                                <tr key={s.locationid} className={s.errors > 0 ? 'bg-red-50' : 'bg-white'}>
                                  <td className="px-3 py-2 font-medium text-slate-800">
                                    {s.locationname || `Outlet ${s.locationid}`}
                                    <span className="ml-1.5 font-mono text-[10px] text-slate-400">#{s.locationid}</span>
                                  </td>
                                  <td className="px-3 py-2 text-right text-slate-600">{s.lines}</td>
                                  <td className="px-3 py-2 text-right text-slate-600">{s.units}</td>
                                  <td className="px-3 py-2 text-right font-semibold text-slate-800">{money(s.amount)}</td>
                                  <td
                                    className={`px-3 py-2 text-right font-semibold ${
                                      s.errors > 0 ? 'text-red-700' : 'text-emerald-700'
                                    }`}
                                  >
                                    {s.errors}
                                  </td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>
                      )}

                      {summary.errors > 0 && (
                        <p className="mb-3 flex items-center gap-2 rounded border border-red-200 bg-red-50 px-3 py-2 text-xs font-medium text-red-800">
                          <XCircle size={14} />
                          {summary.errors} row{summary.errors === 1 ? '' : 's'} must be fixed in the file before this can be
                          uploaded.
                        </p>
                      )}
                      {summary.errors === 0 && summary.warnings > 0 && (
                        <p className="mb-3 flex items-center gap-2 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-xs font-medium text-amber-800">
                          <AlertTriangle size={14} />
                          {summary.warnings} row{summary.warnings === 1 ? '' : 's'} have warnings. You can still upload.
                        </p>
                      )}
                      {parsed.skipped > 0 && (
                        <p className="mb-3 text-xs text-slate-500">
                          {parsed.skipped} row{parsed.skipped === 1 ? '' : 's'} had no quantity and were ignored.
                        </p>
                      )}

                      <div className="max-h-72 overflow-auto rounded-lg border border-slate-200">
                        <table className="w-full min-w-[920px] text-left text-xs">
                          <thead className="sticky top-0 bg-slate-100 text-[11px] uppercase tracking-wide text-slate-600">
                            <tr>
                              <th className="px-3 py-2 font-semibold">Row</th>
                              <th className="px-3 py-2 font-semibold">Store</th>
                              <th className="px-3 py-2 font-semibold">Product</th>
                              <th className="px-3 py-2 text-right font-semibold">Qty</th>
                              <th className="px-3 py-2 text-right font-semibold">Price</th>
                              <th className="px-3 py-2 text-right font-semibold">Amount</th>
                              <th className="px-3 py-2 font-semibold">Bill</th>
                              <th className="px-3 py-2 font-semibold">Status</th>
                            </tr>
                          </thead>
                          <tbody className="divide-y divide-slate-100">
                            {parsed.rows.map((r) => {
                              const bad = r.errors.length > 0;
                              const warn = !bad && r.warnings.length > 0;
                              return (
                                <tr
                                  key={r.excelRow}
                                  className={bad ? 'bg-red-50' : warn ? 'bg-amber-50' : 'bg-white'}
                                >
                                  <td className="px-3 py-2 font-mono text-slate-500">{r.excelRow}</td>
                                  <td className="px-3 py-2 text-slate-700">
                                    {r.locationname || `#${r.locationid}`}
                                  </td>
                                  <td className="px-3 py-2">
                                    <span className="font-medium text-slate-800">{r.productname || '—'}</span>
                                    <span className="ml-1.5 font-mono text-[10px] text-slate-400">#{r.productid}</span>
                                  </td>
                                  <td className="px-3 py-2 text-right font-semibold text-slate-800">{r.qtysold}</td>
                                  <td className="px-3 py-2 text-right text-slate-600">
                                    {r.unitprice ? money(r.unitprice) : <span className="text-amber-600">—</span>}
                                  </td>
                                  <td className="px-3 py-2 text-right text-slate-600">
                                    {money(Math.max(0, (r.unitprice ?? 0) * r.qtysold - r.discountamount))}
                                  </td>
                                  <td className="px-3 py-2 font-mono text-slate-500">{r.billno || '—'}</td>
                                  <td className="px-3 py-2">
                                    {bad ? (
                                      <span className="text-red-700">{r.errors.join('; ')}</span>
                                    ) : warn ? (
                                      <span className="text-amber-700">{r.warnings.join('; ')}</span>
                                    ) : (
                                      <span className="flex items-center gap-1 text-emerald-700">
                                        <CheckCircle2 size={12} /> ready
                                      </span>
                                    )}
                                  </td>
                                </tr>
                              );
                            })}
                          </tbody>
                        </table>
                      </div>
                    </>
                  )}

                  {uploadError && (
                    <p className="mt-4 rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800">
                      {uploadError}
                    </p>
                  )}
                </section>
              )}
            </>
          )}
        </div>

        {!result && (
          <div className="flex shrink-0 items-center justify-between gap-3 border-t border-slate-200 bg-slate-50 px-6 py-4">
            <p className="text-xs text-slate-500">
              Each sale is deducted from the store named on its own row, and appears in Orders marked{' '}
              <span className="font-semibold">OFFLINE</span>. Re-uploading the same file will not deduct twice.
            </p>
            <div className="flex items-center gap-3">
              {parsed && (
                <button
                  onClick={reset}
                  className="flex items-center gap-1.5 rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-100"
                >
                  <RotateCcw size={14} /> Clear
                </button>
              )}
              <button
                onClick={() => uploadMutation.mutate()}
                disabled={!parsed || blocked || uploadMutation.isPending}
                className="flex items-center gap-2 rounded-lg bg-[#662582] px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-[#551f6d] disabled:cursor-not-allowed disabled:opacity-40"
              >
                {uploadMutation.isPending ? (
                  <>
                    <Loader2 size={16} className="animate-spin" /> Importing…
                  </>
                ) : (
                  <>
                    <Upload size={16} /> Import{' '}
                    {summary?.bills ? `${summary.bills} Bill${summary.bills === 1 ? '' : 's'}` : 'Sales'}
                  </>
                )}
              </button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function Stat({ label, value, tone }: { label: string; value: string; tone?: 'good' | 'bad' }) {
  const valueTone = tone === 'bad' ? 'text-red-700' : tone === 'good' ? 'text-emerald-700' : 'text-slate-900';
  return (
    <div className="rounded-lg border border-slate-200 bg-white px-3 py-2">
      <p className="text-[10px] font-semibold uppercase tracking-wide text-slate-500">{label}</p>
      <p className={`text-base font-bold ${valueTone}`}>{value}</p>
    </div>
  );
}

/**
 * Per-bill outcome. Duplicates are reported as their own neutral category
 * rather than as failures: a re-upload being refused is the safeguard working,
 * and calling it an error would push people towards "fixing" it.
 */
function ResultPanel({
  result,
  onAnother,
  onClose,
}: {
  result: OfflineSalesUploadResponse;
  onAnother: () => void;
  onClose: () => void;
}) {
  return (
    <div>
      <div className="mb-5 flex items-start gap-3 rounded-lg border border-slate-200 bg-slate-50 p-5">
        {result.imported > 0 ? (
          <CheckCircle2 size={22} className="mt-0.5 shrink-0 text-emerald-600" />
        ) : (
          <AlertTriangle size={22} className="mt-0.5 shrink-0 text-amber-600" />
        )}
        <div>
          <h3 className="text-base font-bold text-slate-900">
            {result.imported > 0
              ? `${result.imported} bill${result.imported === 1 ? '' : 's'} imported`
              : 'Nothing was imported'}
          </h3>
          <p className="mt-1 text-sm text-slate-600">
            {result.imported > 0 && <>Stock has been reduced and {money(result.totalamount)} recorded as revenue. </>}
            {result.duplicate > 0 && (
              <>
                {result.duplicate} bill{result.duplicate === 1 ? ' was' : 's were'} already imported and{' '}
                {result.duplicate === 1 ? 'was' : 'were'} skipped.{' '}
              </>
            )}
            {result.failed > 0 && (
              <>
                {result.failed} bill{result.failed === 1 ? '' : 's'} could not be imported — see below.
              </>
            )}
          </p>
        </div>
      </div>

      <div className="overflow-hidden rounded-lg border border-slate-200">
        <table className="w-full text-left text-xs">
          <thead className="bg-slate-100 text-[11px] uppercase tracking-wide text-slate-600">
            <tr>
              <th className="px-3 py-2 font-semibold">Store</th>
              <th className="px-3 py-2 font-semibold">Bill</th>
              <th className="px-3 py-2 font-semibold">Result</th>
              <th className="px-3 py-2 font-semibold">Order</th>
              <th className="px-3 py-2 text-right font-semibold">Items</th>
              <th className="px-3 py-2 text-right font-semibold">Amount</th>
              <th className="px-3 py-2 font-semibold">Detail</th>
            </tr>
          </thead>
          <tbody className="divide-y divide-slate-100">
            {result.results.map((r, i) => (
              <tr
                key={`${r.locationid}-${r.billno}-${i}`}
                className={
                  r.status === 'imported' ? 'bg-white' : r.status === 'duplicate' ? 'bg-slate-50' : 'bg-red-50'
                }
              >
                <td className="px-3 py-2 text-slate-700">{r.locationname || (r.locationid ? `#${r.locationid}` : '—')}</td>
                <td className="px-3 py-2 font-mono text-slate-700">{r.billno || '—'}</td>
                <td className="px-3 py-2">
                  {r.status === 'imported' && (
                    <span className="rounded bg-emerald-100 px-2 py-0.5 font-semibold text-emerald-800">imported</span>
                  )}
                  {r.status === 'duplicate' && (
                    <span className="rounded bg-slate-200 px-2 py-0.5 font-semibold text-slate-700">already done</span>
                  )}
                  {r.status === 'failed' && (
                    <span className="rounded bg-red-100 px-2 py-0.5 font-semibold text-red-800">failed</span>
                  )}
                </td>
                <td className="px-3 py-2 font-mono text-slate-600">{r.orderid || '—'}</td>
                <td className="px-3 py-2 text-right text-slate-600">{r.itemcount || '—'}</td>
                <td className="px-3 py-2 text-right text-slate-600">{r.amount ? money(r.amount) : '—'}</td>
                <td className="px-3 py-2 text-slate-600">{r.message}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      <div className="mt-6 flex justify-end gap-3">
        <button
          onClick={onAnother}
          className="rounded-lg border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 transition-colors hover:bg-slate-100"
        >
          Upload Another File
        </button>
        <button
          onClick={onClose}
          className="rounded-lg bg-[#662582] px-5 py-2 text-sm font-semibold text-white transition-colors hover:bg-[#551f6d]"
        >
          Done
        </button>
      </div>
    </div>
  );
}
