import { useEffect, useMemo, useState } from "react";
import { createFileRoute, Link } from "@tanstack/react-router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  Loader2,
  Stethoscope,
  Globe,
  Star,
  Sparkles,
  AlertTriangle,
  PlusCircle,
  Trash2,
  Save,
  RefreshCw,
  ArrowRight,
  Target,
  Share2,
  ShoppingBag,
  Search,
  MessageCircle,
} from "lucide-react";
import { AppShell } from "@/components/AppShell";
import { PortfolioPrompt } from "@/components/PortfolioPrompt";
import { PageHeader } from "@/components/PageHeader";
import { Sources } from "@/components/Sources";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import { useBriefing } from "@/hooks/useBriefing";
import { supabase } from "@/integrations/supabase/client";
import {
  runSelfExamination,
  type SelfExam,
  type SocialProfile,
  type OtaListing,
} from "@/lib/selfExamination.functions";
import { authHeaders } from "@/lib/authHeaders";

export const Route = createFileRoute("/self-examination")({
  head: () => ({
    meta: [
      { title: "Self-Examination — The Daily Ledger" },
      {
        name: "description",
        content:
          "AI-powered audit of your hotel's website, SEO, OTA presence, social media, reviews and branding — with concrete suggestions to fix gaps.",
      },
      { property: "og:title", content: "Self-Examination — The Daily Ledger" },
      {
        property: "og:description",
        content:
          "Scan your hotel's full digital footprint and get prioritised improvements with citations.",
      },
    ],
  }),
  component: SelfExaminationPage,
});

type DbRow = {
  id: string;
  hotel_id: string;
  website_url: string | null;
  social_profiles: SocialProfile[] | null;
  ota_listings: OtaListing[] | null;
  seo_data: SelfExam["seo_data"] | null;
  reviews: SelfExam["reviews"] | null;
  branding: SelfExam["branding"] | null;
  suggestions: SelfExam["suggestions"] | null;
  manual_notes: string | null;
  manual_overrides: {
    social_profiles?: SocialProfile[];
    ota_listings?: OtaListing[];
    website_url?: string | null;
  } | null;
  sources: SelfExam["sources"] | null;
  last_scanned_at: string | null;
};

const PLATFORMS: SocialProfile["platform"][] = [
  "facebook",
  "instagram",
  "tiktok",
  "x",
  "youtube",
  "linkedin",
  "threads",
  "xiaohongshu",
  "wechat",
  "other",
];

function SelfExaminationPage() {
  const { hotel, isAllHotels, isHotelLoading } = useBriefing();
  const qc = useQueryClient();
  const [websiteHint, setWebsiteHint] = useState("");
  const [manualNotes, setManualNotes] = useState("");
  const [manualSocials, setManualSocials] = useState<SocialProfile[]>([]);
  const [manualOtas, setManualOtas] = useState<OtaListing[]>([]);

  // Load saved row
  const rowQuery = useQuery({
    queryKey: ["self-exam", hotel?.id],
    enabled: !!hotel?.id,
    queryFn: async () => {
      const { data, error } = await supabase
        .from("self_examinations")
        .select("*")
        .eq("hotel_id", hotel!.id)
        .maybeSingle();
      if (error) throw error;
      return (data as DbRow | null) ?? null;
    },
  });

  // Hydrate manual fields when row loads
  useEffect(() => {
    if (rowQuery.data) {
      setWebsiteHint(rowQuery.data.website_url ?? rowQuery.data.manual_overrides?.website_url ?? "");
      setManualNotes(rowQuery.data.manual_notes ?? "");
      setManualSocials(rowQuery.data.manual_overrides?.social_profiles ?? []);
      setManualOtas(rowQuery.data.manual_overrides?.ota_listings ?? []);
    }
  }, [rowQuery.data]);

  const audit: SelfExam | null = useMemo(() => {
    const r = rowQuery.data;
    // Only treat the row as a real audit when an actual scan has run.
    // Manual-only saves (Save inputs before scanning) leave last_scanned_at null.
    if (!r || !r.seo_data || !r.last_scanned_at) return null;
    return {
      website_url: r.website_url,
      seo_data: r.seo_data,
      ota_listings: r.ota_listings ?? [],
      social_profiles: r.social_profiles ?? [],
      reviews: r.reviews ?? {},
      branding: r.branding ?? { brand_clarity: "okay", visual_consistency: "unknown" },
      suggestions: r.suggestions ?? [],
      sources: r.sources ?? [],
      health_score: (r.seo_data as unknown as { health_score?: number })?.health_score ?? 0,
    } as unknown as SelfExam;
  }, [rowQuery.data]);

  // Run scan + persist
  const scanMutation = useMutation({
    mutationFn: async () => {
      if (!hotel) throw new Error("No hotel");
      const result = await runSelfExamination({
        data: {
          hotelName: hotel.hotel_name,
          location: hotel.location,
          websiteUrlHint: websiteHint || null,
          manualNotes: manualNotes || null,
          manualOverrides: {
            social_profiles: manualSocials,
            ota_listings: manualOtas,
            website_url: websiteHint || null,
          },
        },
        headers: await authHeaders(),
      });
      // Upsert into DB
      const { data: userRes } = await supabase.auth.getUser();
      const userId = userRes.user?.id;
      if (!userId) throw new Error("Not authenticated");
      const payload = {
        hotel_id: hotel.id,
        user_id: userId,
        website_url: result.website_url ?? websiteHint ?? null,
        social_profiles: result.social_profiles,
        ota_listings: result.ota_listings,
        seo_data: { ...result.seo_data, health_score: result.health_score },
        reviews: result.reviews,
        branding: result.branding,
        suggestions: result.suggestions,
        sources: result.sources,
        manual_notes: manualNotes || null,
        manual_overrides: {
          social_profiles: manualSocials,
          ota_listings: manualOtas,
          website_url: websiteHint || null,
        },
        last_scanned_at: new Date().toISOString(),
      };
      const { error } = await supabase
        .from("self_examinations")
        .upsert(payload, { onConflict: "hotel_id" });
      if (error) throw error;
      return result;
    },
    onSuccess: () => {
      toast.success("Self-examination updated");
      qc.invalidateQueries({ queryKey: ["self-exam", hotel?.id] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  // Save manual data only (without rescanning)
  const saveManualMutation = useMutation({
    mutationFn: async () => {
      if (!hotel) throw new Error("No hotel");
      const { data: userRes } = await supabase.auth.getUser();
      const userId = userRes.user?.id;
      if (!userId) throw new Error("Not authenticated");
      const existing = rowQuery.data;
      const payload = {
        hotel_id: hotel.id,
        user_id: userId,
        website_url: existing?.website_url ?? websiteHint ?? null,
        social_profiles: existing?.social_profiles ?? [],
        ota_listings: existing?.ota_listings ?? [],
        seo_data: existing?.seo_data ?? { has_official_website: false },
        reviews: existing?.reviews ?? {},
        branding: existing?.branding ?? { brand_clarity: "okay", visual_consistency: "unknown" },
        suggestions: existing?.suggestions ?? [],
        sources: existing?.sources ?? [],
        manual_notes: manualNotes || null,
        manual_overrides: {
          social_profiles: manualSocials,
          ota_listings: manualOtas,
          website_url: websiteHint || null,
        },
        last_scanned_at: existing?.last_scanned_at ?? null,
      };
      const { error } = await supabase
        .from("self_examinations")
        .upsert(payload, { onConflict: "hotel_id" });
      if (error) throw error;
    },
    onSuccess: () => {
      toast.success("Saved");
      qc.invalidateQueries({ queryKey: ["self-exam", hotel?.id] });
    },
    onError: (e: Error) => toast.error(e.message),
  });

  if (isHotelLoading) {
    return (
      <div className="flex min-h-dvh items-center justify-center">
        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
      </div>
    );
  }
  if (isAllHotels || !hotel) return <PortfolioPrompt pageTitle="Self-Exam" />;

  const isScanning = scanMutation.isPending;
  const lastScannedAt = rowQuery.data?.last_scanned_at
    ? new Date(rowQuery.data.last_scanned_at).toLocaleString()
    : null;

  return (
    <AppShell hotel={hotel} isLoading={isScanning} onRefresh={() => scanMutation.mutate()}>
      <PageHeader
        eyebrow="Self-examination"
        title={`How ${hotel.hotel_name} shows up online`}
        subtitle="We scan your website, OTA listings, social profiles and reviews — then tell you what's missing and what to fix."
      />

      {/* Action bar */}
      <div className="mb-6 flex flex-wrap items-center justify-between gap-3 rounded-2xl border bg-card p-4 shadow-[var(--shadow-elegant)]">
        <div className="text-xs text-muted-foreground">
          {lastScannedAt ? <>Last scan: <span className="text-foreground">{lastScannedAt}</span></> : "No scan yet"}
        </div>
        <Button onClick={() => scanMutation.mutate()} disabled={isScanning} className="gap-2">
          {isScanning ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCw className="h-4 w-4" />}
          {audit ? "Re-scan now" : "Run audit"}
        </Button>
      </div>

      {/* Manual inputs */}
      <article className="mb-8 rounded-2xl border bg-card p-6 shadow-[var(--shadow-elegant)]">
        <div className="mb-4 flex items-center gap-2 text-xs uppercase tracking-[0.18em] text-accent">
          <Sparkles className="h-3.5 w-3.5" /> Optional — help us be more accurate
        </div>

        <div className="grid gap-4 md:grid-cols-2">
          <div>
            <Label htmlFor="website" className="text-xs uppercase tracking-wider text-muted-foreground">
              Official website URL
            </Label>
            <Input
              id="website"
              placeholder="https://www.yourhotel.com"
              value={websiteHint}
              onChange={(e) => setWebsiteHint(e.target.value)}
              className="mt-1"
            />
          </div>
          <div>
            <Label htmlFor="notes" className="text-xs uppercase tracking-wider text-muted-foreground">
              Notes for the auditor
            </Label>
            <Input
              id="notes"
              placeholder="e.g. We just rebranded, no TikTok yet"
              value={manualNotes}
              onChange={(e) => setManualNotes(e.target.value)}
              className="mt-1"
            />
          </div>
        </div>

        {/* Manual social entries */}
        <div className="mt-6">
          <div className="mb-2 flex items-center justify-between">
            <Label className="text-xs uppercase tracking-wider text-muted-foreground">
              Social profiles you control
            </Label>
            <Button
              type="button"
              size="sm"
              variant="ghost"
              onClick={() =>
                setManualSocials((s) => [
                  ...s,
                  { platform: "instagram", handle: "", url: "", activity: "active" },
                ])
              }
              className="gap-1 text-xs"
            >
              <PlusCircle className="h-3.5 w-3.5" /> Add
            </Button>
          </div>
          <div className="space-y-2">
            {manualSocials.map((s, idx) => (
              <div key={idx} className="grid grid-cols-1 gap-2 sm:grid-cols-[140px_1fr_auto]">
                <select
                  value={s.platform}
                  onChange={(e) => {
                    const v = e.target.value as SocialProfile["platform"];
                    setManualSocials((arr) =>
                      arr.map((x, i) => (i === idx ? { ...x, platform: v } : x)),
                    );
                  }}
                  className="h-9 rounded-md border bg-background px-2 text-sm capitalize"
                >
                  {PLATFORMS.map((p) => (
                    <option key={p} value={p}>
                      {p}
                    </option>
                  ))}
                </select>
                <Input
                  placeholder="URL or @handle"
                  value={s.url ?? s.handle ?? ""}
                  onChange={(e) => {
                    const v = e.target.value;
                    setManualSocials((arr) =>
                      arr.map((x, i) =>
                        i === idx
                          ? { ...x, url: v.startsWith("http") ? v : null, handle: v.startsWith("http") ? null : v }
                          : x,
                      ),
                    );
                  }}
                />
                <Button
                  type="button"
                  size="icon"
                  variant="ghost"
                  onClick={() => setManualSocials((arr) => arr.filter((_, i) => i !== idx))}
                  className="h-9 w-9"
                  aria-label="Remove"
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              </div>
            ))}
            {manualSocials.length === 0 && (
              <p className="text-xs italic text-muted-foreground">None added — we'll discover what we can.</p>
            )}
          </div>
        </div>

        {/* Manual OTA entries */}
        <div className="mt-6">
          <div className="mb-2 flex items-center justify-between">
            <Label className="text-xs uppercase tracking-wider text-muted-foreground">
              OTA listings you know about
            </Label>
            <Button
              type="button"
              size="sm"
              variant="ghost"
              onClick={() =>
                setManualOtas((s) => [...s, { channel: "Booking.com", url: "" }])
              }
              className="gap-1 text-xs"
            >
              <PlusCircle className="h-3.5 w-3.5" /> Add
            </Button>
          </div>
          <div className="space-y-2">
            {manualOtas.map((o, idx) => (
              <div key={idx} className="grid grid-cols-1 gap-2 sm:grid-cols-[160px_1fr_auto]">
                <Input
                  placeholder="Channel"
                  value={o.channel}
                  onChange={(e) => {
                    const v = e.target.value;
                    setManualOtas((arr) =>
                      arr.map((x, i) => (i === idx ? { ...x, channel: v } : x)),
                    );
                  }}
                />
                <Input
                  placeholder="Listing URL"
                  value={o.url ?? ""}
                  onChange={(e) => {
                    const v = e.target.value;
                    setManualOtas((arr) =>
                      arr.map((x, i) => (i === idx ? { ...x, url: v } : x)),
                    );
                  }}
                />
                <Button
                  type="button"
                  size="icon"
                  variant="ghost"
                  onClick={() => setManualOtas((arr) => arr.filter((_, i) => i !== idx))}
                  className="h-9 w-9"
                  aria-label="Remove"
                >
                  <Trash2 className="h-4 w-4" />
                </Button>
              </div>
            ))}
            {manualOtas.length === 0 && (
              <p className="text-xs italic text-muted-foreground">None added — we'll discover what we can.</p>
            )}
          </div>
        </div>

        <div className="mt-5">
          <Textarea
            placeholder="Anything else the auditor should know about your digital strategy..."
            value={manualNotes}
            onChange={(e) => setManualNotes(e.target.value)}
            className="min-h-20"
          />
        </div>

        <div className="mt-4 flex justify-end">
          <Button
            type="button"
            size="sm"
            variant="outline"
            onClick={() => saveManualMutation.mutate()}
            disabled={saveManualMutation.isPending}
            className="gap-2"
          >
            {saveManualMutation.isPending ? (
              <Loader2 className="h-3.5 w-3.5 animate-spin" />
            ) : (
              <Save className="h-3.5 w-3.5" />
            )}
            Save inputs
          </Button>
        </div>
      </article>

      {rowQuery.isLoading ? (
        <div className="flex items-center justify-center py-12">
          <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
        </div>
      ) : isScanning && !audit ? (
        <div className="rounded-2xl border bg-card p-12 text-center text-muted-foreground">
          <Loader2 className="mx-auto mb-3 h-6 w-6 animate-spin" />
          Scanning the web for {hotel.hotel_name}…
        </div>
      ) : !audit ? (
        <div className="rounded-2xl border-2 border-dashed bg-card/50 p-10 text-center">
          <Stethoscope className="mx-auto mb-3 h-8 w-8 text-muted-foreground" />
          <p className="font-serif text-lg text-foreground">No audit yet</p>
          <p className="mt-1 text-sm text-muted-foreground">
            Click <strong>Run audit</strong> to scan your hotel's digital presence.
          </p>
        </div>
      ) : (
        <AuditView audit={audit} currency={hotel.currency || "MYR"} />
      )}
    </AppShell>
  );
}

// =================== Audit summary view ===================

type SectionKey = "health" | "fix" | "social" | "ota" | "seo" | "reviews" | "branding";

function SummaryCard({
  section,
  title,
  eyebrow,
  icon: Icon,
  children,
  accent,
}: {
  section: SectionKey;
  title: string;
  eyebrow: string;
  icon: typeof Globe;
  children: React.ReactNode;
  accent?: string;
}) {
  return (
    <Link
      to="/self-exam-detail"
      search={{ section }}
      className="group block rounded-2xl border bg-card p-5 shadow-sm transition-all hover:border-brand/40 hover:shadow-[var(--shadow-elegant)]"
    >
      <div className="mb-3 flex items-center justify-between gap-2">
        <div className={`inline-flex items-center gap-2 text-[11px] uppercase tracking-[0.18em] ${accent ?? "text-muted-foreground"}`}>
          <Icon className="h-3.5 w-3.5" /> {eyebrow}
        </div>
        <ArrowRight className="h-4 w-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-brand" />
      </div>
      <h3 className="mb-2 font-serif text-lg text-foreground">{title}</h3>
      <div className="text-sm text-muted-foreground">{children}</div>
    </Link>
  );
}

function AuditView({ audit, currency: _currency }: { audit: SelfExam; currency: string }) {
  const score = Math.round(audit.health_score ?? 0);
  const scoreColor =
    score >= 75 ? "text-emerald-600" : score >= 50 ? "text-amber-600" : "text-destructive";
  const criticalCount = audit.suggestions.filter((s) => s.severity === "critical").length;
  const activeSocials = audit.social_profiles.filter((s) => s.activity === "active").length;
  const totalSocials = audit.social_profiles.length;
  const otaCount = audit.ota_listings.length;
  const topOta = [...audit.ota_listings]
    .filter((o) => o.rating != null)
    .sort((a, b) => (b.rating ?? 0) - (a.rating ?? 0))[0];

  return (
    <div className="space-y-6">
      {/* Health score hero */}
      <Link
        to="/self-exam-detail"
        search={{ section: "health" }}
        className="group block rounded-2xl border bg-gradient-to-br from-brand-soft/40 to-card p-5 shadow-[var(--shadow-elegant)] transition-all hover:border-brand/40 sm:p-8"
      >
        <div className="flex flex-wrap items-end justify-between gap-4">
          <div>
            <div className="text-xs uppercase tracking-[0.18em] text-muted-foreground">
              Digital health score
            </div>
            <div className={`font-serif text-5xl font-medium sm:text-6xl ${scoreColor}`}>{score}</div>
            <div className="text-xs text-muted-foreground">out of 100 — tap for breakdown & sources</div>
          </div>
          {audit.website_url ? (
            <a
              href={audit.website_url}
              target="_blank"
              rel="noopener noreferrer"
              onClick={(e) => e.stopPropagation()}
              className="inline-flex items-center gap-1.5 text-sm text-brand hover:underline"
            >
              <Globe className="h-3.5 w-3.5" /> {audit.website_url}
            </a>
          ) : null}
        </div>
      </Link>

      {/* Section summary cards */}
      <div className="grid gap-4 md:grid-cols-2">
        <SummaryCard
          section="fix"
          eyebrow="What to fix"
          title={
            criticalCount > 0
              ? `${criticalCount} critical · ${audit.suggestions.length} total`
              : `${audit.suggestions.length} suggestions`
          }
          icon={AlertTriangle}
          accent={criticalCount > 0 ? "text-destructive" : "text-amber-600"}
        >
          {audit.suggestions[0] ? (
            <p className="line-clamp-2">{audit.suggestions[0].finding}</p>
          ) : (
            <p className="italic">No issues detected.</p>
          )}
        </SummaryCard>

        <SummaryCard
          section="social"
          eyebrow="Social presence"
          title={`${activeSocials} active of ${totalSocials} channels`}
          icon={Share2}
        >
          <div className="flex flex-wrap gap-1.5">
            {audit.social_profiles.slice(0, 5).map((s, i) => (
              <Badge key={i} variant="outline" className="capitalize text-[10px]">
                {s.platform} · {s.activity}
              </Badge>
            ))}
          </div>
        </SummaryCard>

        <SummaryCard
          section="ota"
          eyebrow="OTA presence"
          title={otaCount > 0 ? `Listed on ${otaCount} channels` : "No OTAs detected"}
          icon={ShoppingBag}
        >
          {topOta ? (
            <p className="inline-flex items-center gap-1">
              Best: <strong className="text-foreground">{topOta.channel}</strong>
              <span className="inline-flex items-center gap-0.5 text-amber-600">
                <Star className="h-3 w-3 fill-current" /> {topOta.rating?.toFixed(1)}
              </span>
            </p>
          ) : (
            <p className="italic">No ratings detected.</p>
          )}
        </SummaryCard>

        <SummaryCard
          section="seo"
          eyebrow="Website & SEO"
          title={
            audit.seo_data.has_official_website
              ? audit.seo_data.estimated_search_ranking ?? "Site detected"
              : "No official website detected"
          }
          icon={Search}
        >
          <div className="flex flex-wrap gap-1.5">
            <Badge variant="outline" className="text-[10px]">
              HTTPS: {fmtBool(audit.seo_data.has_https)}
            </Badge>
            <Badge variant="outline" className="text-[10px]">
              Mobile: {fmtBool(audit.seo_data.mobile_friendly)}
            </Badge>
            <Badge variant="outline" className="text-[10px]">
              Booking: {fmtBool(audit.seo_data.has_booking_engine)}
            </Badge>
          </div>
        </SummaryCard>

        <SummaryCard
          section="reviews"
          eyebrow="Reviews"
          title={
            audit.reviews.avg_rating != null
              ? `${audit.reviews.avg_rating.toFixed(1)} avg${
                  audit.reviews.total_reviews ? ` · ${audit.reviews.total_reviews} reviews` : ""
                }`
              : "No aggregated rating"
          }
          icon={MessageCircle}
        >
          {audit.reviews.best_quote ? (
            <p className="line-clamp-2 italic">"{audit.reviews.best_quote}"</p>
          ) : (
            <p className="italic">No quotes captured yet.</p>
          )}
        </SummaryCard>

        <SummaryCard
          section="branding"
          eyebrow="Branding"
          title={`Clarity: ${audit.branding.brand_clarity} · Visuals: ${audit.branding.visual_consistency}`}
          icon={Sparkles}
        >
          {audit.branding.tagline ? (
            <p className="line-clamp-2 italic">"{audit.branding.tagline}"</p>
          ) : (
            <p className="italic">No tagline detected.</p>
          )}
        </SummaryCard>
      </div>

      {/* Actions CTA */}
      <article className="rounded-2xl border border-brand/30 bg-gradient-to-br from-brand-soft/30 to-card p-6 shadow-[var(--shadow-elegant)]">
        <div className="flex flex-wrap items-center justify-between gap-4">
          <div>
            <div className="mb-1 inline-flex items-center gap-1.5 text-xs uppercase tracking-[0.18em] text-brand">
              <Target className="h-3.5 w-3.5" /> Turn this audit into action
            </div>
            <h3 className="font-serif text-xl text-foreground">Suggested moves based on these findings</h3>
            <p className="mt-1 text-sm text-muted-foreground">
              Open your Action Plan to see today's three priority moves.
            </p>
          </div>
          <Button asChild className="gap-2">
            <Link to="/actions">
              View actions <ArrowRight className="h-4 w-4" />
            </Link>
          </Button>
        </div>
      </article>
    </div>
  );
}

function fmtBool(v?: boolean | null) {
  if (v === true) return "Yes";
  if (v === false) return "No";
  return "Unknown";
}

