import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { supabase } from "@/integrations/supabase/client";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import { Paperclip, Download, FileText, Eye, Upload, X as XIcon, CheckCircle2 } from "lucide-react";

export const Route = createFileRoute("/admin/requests")({ component: RequestsAdmin });

type Req = {
  id: string;
  service_name: string;
  contact_name: string;
  contact_phone: string;
  contact_email: string | null;
  notes: string | null;
  admin_notes: string | null;
  status: "pending" | "processing" | "completed" | "cancelled";
  created_at: string;
  attachments: { path: string; name: string; size: number; type: string }[] | null;
  user_id: string | null;
  price: number | null;
  paid: boolean;
  delivery_notes: string | null;
  deliverables: { path: string; name: string; size: number; type: string }[] | null;
  delivered_at: string | null;
};

const STATUSES: Req["status"][] = ["pending", "processing", "completed", "cancelled"];

function RequestsAdmin() {
  const [rows, setRows] = useState<Req[]>([]);
  const [filter, setFilter] = useState<"all" | Req["status"]>("all");

  const load = async () => {
    const { data, error } = await supabase
      .from("service_requests")
      .select("id, user_id, service_name, contact_name, contact_phone, contact_email, notes, admin_notes, status, created_at, attachments, price, paid, delivery_notes, deliverables, delivered_at")
      .order("created_at", { ascending: false });
    if (error) toast.error(error.message);
    else setRows((data ?? []) as Req[]);
  };
  useEffect(() => { load(); }, []);

  const updateRow = async (id: string, patch: Partial<Req>) => {
    const { error } = await supabase.from("service_requests").update(patch).eq("id", id);
    if (error) return toast.error(error.message);
    setRows((rs) => rs.map((r) => (r.id === id ? { ...r, ...patch } : r)));
    toast.success("Updated");
  };

  const filtered = filter === "all" ? rows : rows.filter((r) => r.status === filter);

  return (
    <div className="space-y-6">
      <div>
        <h1 className="text-2xl font-bold tracking-tight">Service requests</h1>
        <p className="text-sm text-muted-foreground">Track and update customer service requests.</p>
      </div>
      <div className="flex flex-wrap gap-2">
        {(["all", ...STATUSES] as const).map((s) => (
          <Button key={s} size="sm" variant={filter === s ? "default" : "outline"} onClick={() => setFilter(s)} className="capitalize">
            {s}
          </Button>
        ))}
      </div>
      <div className="grid gap-3">
        {filtered.length === 0 && <p className="text-sm text-muted-foreground">No requests.</p>}
        {filtered.map((r) => (
          <Card key={r.id} className="glass">
            <CardHeader className="flex flex-row items-start justify-between gap-2 space-y-0">
              <div>
                <div className="font-semibold">{r.service_name}</div>
                <div className="text-xs text-muted-foreground">
                  {r.contact_name} · {r.contact_phone}{r.contact_email ? ` · ${r.contact_email}` : ""}
                </div>
                <div className="text-xs text-muted-foreground">{new Date(r.created_at).toLocaleString()}</div>
              </div>
              <select
                value={r.status}
                onChange={(e) => updateRow(r.id, { status: e.target.value as Req["status"] })}
                className="rounded-md border bg-background px-2 py-1 text-xs capitalize"
              >
                {STATUSES.map((s) => <option key={s} value={s}>{s}</option>)}
              </select>
            </CardHeader>
            <CardContent className="space-y-2">
              {r.notes && <div className="text-sm"><span className="font-medium">Customer notes:</span> {r.notes}</div>}
              {r.attachments && r.attachments.length > 0 && (
                <AttachmentsPanel attachments={r.attachments} />
              )}
              <PricingPanel r={r} onSave={(patch) => updateRow(r.id, patch)} />
              <DeliveryPanel r={r} onChange={load} />
              <AdminNoteEditor value={r.admin_notes ?? ""} onSave={(v) => updateRow(r.id, { admin_notes: v })} />
            </CardContent>
          </Card>
        ))}
      </div>
    </div>
  );
}

function PricingPanel({ r, onSave }: { r: Req; onSave: (patch: Partial<Req>) => void }) {
  const [price, setPrice] = useState<string>(r.price != null ? String(r.price) : "");
  useEffect(() => { setPrice(r.price != null ? String(r.price) : ""); }, [r.price]);
  return (
    <div className="flex flex-wrap items-end gap-2 rounded-lg border bg-background/50 p-3">
      <div className="grow space-y-1">
        <Label className="text-xs text-muted-foreground">Service price (KSh)</Label>
        <Input type="number" value={price} onChange={(e) => setPrice(e.target.value)} placeholder="e.g. 500" />
      </div>
      <Button size="sm" variant="outline" onClick={() => onSave({ price: price ? Number(price) : null })}>Save price</Button>
      {r.paid ? (
        <Badge className="gap-1"><CheckCircle2 className="h-3 w-3"/> Paid</Badge>
      ) : (
        <Badge variant="secondary">Unpaid</Badge>
      )}
    </div>
  );
}

type Deliverable = { path: string; name: string; size: number; type: string };

function DeliveryPanel({ r, onChange }: { r: Req; onChange: () => void }) {
  const [notes, setNotes] = useState(r.delivery_notes ?? "");
  const [files, setFiles] = useState<File[]>([]);
  const [busy, setBusy] = useState(false);
  useEffect(() => setNotes(r.delivery_notes ?? ""), [r.delivery_notes]);

  const deliver = async (markCompleted: boolean) => {
    if (!r.user_id) return toast.error("Request has no user");
    setBusy(true);
    try {
      const uploaded: Deliverable[] = [...(r.deliverables ?? [])];
      for (const f of files) {
        if (f.size > 25 * 1024 * 1024) { toast.error(`${f.name} exceeds 25MB`); continue; }
        const safe = f.name.replace(/[^a-zA-Z0-9._-]/g, "_");
        const path = `${r.user_id}/deliveries/${r.id}/${Date.now()}-${safe}`;
        const up = await supabase.storage.from("request-attachments").upload(path, f, { contentType: f.type || "application/octet-stream" });
        if (up.error) { toast.error(`Upload failed: ${f.name}`); continue; }
        uploaded.push({ path, name: f.name, size: f.size, type: f.type });
      }
      const patch: Partial<Req> = { deliverables: uploaded, delivery_notes: notes || null };
      if (markCompleted) {
        patch.status = "completed";
        patch.delivered_at = new Date().toISOString();
      }
      const { error } = await supabase.from("service_requests").update(patch).eq("id", r.id);
      if (error) throw error;
      toast.success(markCompleted ? "Delivered to customer" : "Saved");
      setFiles([]);
      onChange();
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Failed");
    } finally { setBusy(false); }
  };

  const removeDeliverable = async (path: string) => {
    if (!confirm("Remove this deliverable?")) return;
    await supabase.storage.from("request-attachments").remove([path]);
    const next = (r.deliverables ?? []).filter((d) => d.path !== path);
    await supabase.from("service_requests").update({ deliverables: next }).eq("id", r.id);
    onChange();
  };

  return (
    <div className="space-y-2 rounded-lg border border-primary/20 bg-primary/5 p-3">
      <div className="flex items-center justify-between">
        <div className="text-sm font-semibold">Deliver service</div>
        {r.delivered_at && <span className="text-xs text-muted-foreground">Delivered {new Date(r.delivered_at).toLocaleString()}</span>}
      </div>
      <Textarea rows={2} placeholder="Message to customer with the completed service" value={notes} onChange={(e) => setNotes(e.target.value)} />
      <label className="flex cursor-pointer items-center justify-center gap-2 rounded-md border border-dashed px-3 py-3 text-xs text-muted-foreground hover:bg-muted">
        <Upload className="h-4 w-4" />
        <span>Upload deliverable files (PDFs, images, docs — max 25MB each)</span>
        <input type="file" multiple className="hidden" onChange={(e) => { setFiles((p) => [...p, ...Array.from(e.target.files ?? [])]); e.target.value = ""; }} />
      </label>
      {files.length > 0 && (
        <ul className="space-y-1 text-xs">
          {files.map((f, i) => (
            <li key={i} className="flex items-center justify-between rounded bg-muted/50 px-2 py-1">
              <span className="truncate">{f.name}</span>
              <button onClick={() => setFiles((p) => p.filter((_, j) => j !== i))}><XIcon className="h-3 w-3"/></button>
            </li>
          ))}
        </ul>
      )}
      {r.deliverables && r.deliverables.length > 0 && (
        <div className="space-y-1">
          <div className="text-xs font-medium">Uploaded deliverables:</div>
          <ul className="space-y-1 text-xs">
            {r.deliverables.map((d) => (
              <li key={d.path} className="flex items-center justify-between rounded bg-background px-2 py-1">
                <span className="truncate">{d.name}</span>
                <button onClick={() => removeDeliverable(d.path)} className="text-destructive"><XIcon className="h-3 w-3"/></button>
              </li>
            ))}
          </ul>
        </div>
      )}
      <div className="flex flex-wrap gap-2">
        <Button size="sm" variant="outline" onClick={() => deliver(false)} disabled={busy}>Save draft</Button>
        <Button size="sm" onClick={() => deliver(true)} disabled={busy || (!r.paid && (r.price ?? 0) > 0)}>
          {busy ? "Delivering…" : "Deliver & mark complete"}
        </Button>
        {!r.paid && (r.price ?? 0) > 0 && <span className="self-center text-xs text-muted-foreground">Customer must pay first</span>}
      </div>
    </div>
  );
}

type Attachment = { path: string; name: string; size: number; type: string };

function AttachmentsPanel({ attachments }: { attachments: Attachment[] }) {
  const [urls, setUrls] = useState<Record<string, string>>({});

  useEffect(() => {
    (async () => {
      const entries = await Promise.all(
        attachments.map(async (a) => {
          const { data } = await supabase.storage
            .from("request-attachments")
            .createSignedUrl(a.path, 60 * 30);
          return [a.path, data?.signedUrl ?? ""] as const;
        })
      );
      setUrls(Object.fromEntries(entries));
    })();
  }, [attachments]);

  const download = async (a: Attachment) => {
    const url = urls[a.path];
    if (!url) return toast.error("Preparing file, try again");
    try {
      const res = await fetch(url);
      const blob = await res.blob();
      const objUrl = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = objUrl;
      link.download = a.name;
      document.body.appendChild(link);
      link.click();
      link.remove();
      URL.revokeObjectURL(objUrl);
    } catch {
      window.open(url, "_blank", "noopener,noreferrer");
    }
  };

  return (
    <div className="space-y-2">
      <div className="flex items-center gap-2 text-sm font-medium">
        <Paperclip className="h-3.5 w-3.5" /> Attachments ({attachments.length})
      </div>
      <div className="grid grid-cols-2 gap-2 sm:grid-cols-3 md:grid-cols-4">
        {attachments.map((a) => {
          const url = urls[a.path];
          const isImage = a.type?.startsWith("image/");
          return (
            <div key={a.path} className="group overflow-hidden rounded-lg border bg-background">
              <div className="relative flex h-28 items-center justify-center bg-muted">
                {isImage && url ? (
                  <img src={url} alt={a.name} className="h-full w-full object-cover" loading="lazy" />
                ) : (
                  <FileText className="h-10 w-10 text-muted-foreground" />
                )}
                {url && (
                  <a
                    href={url}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="absolute inset-0 flex items-center justify-center bg-black/50 opacity-0 transition-opacity group-hover:opacity-100"
                    title="Preview"
                  >
                    <Eye className="h-6 w-6 text-white" />
                  </a>
                )}
              </div>
              <div className="space-y-1 p-2">
                <div className="truncate text-xs font-medium" title={a.name}>{a.name}</div>
                <div className="flex items-center justify-between text-[10px] text-muted-foreground">
                  <span>{(a.size / 1024).toFixed(0)} KB</span>
                  <button
                    type="button"
                    onClick={() => download(a)}
                    className="inline-flex items-center gap-1 text-primary hover:underline"
                  >
                    <Download className="h-3 w-3" /> Download
                  </button>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function AdminNoteEditor({ value, onSave }: { value: string; onSave: (v: string) => void }) {
  const [v, setV] = useState(value);
  useEffect(() => setV(value), [value]);
  return (
    <div className="space-y-2">
      <Textarea placeholder="Add internal / customer-facing note" value={v} onChange={(e) => setV(e.target.value)} rows={2} />
      <Button size="sm" onClick={() => onSave(v)}>Save note</Button>
    </div>
  );
}