"use client";

import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { PORTFOLIO_GOALS } from "@/app/db/schema/portfolio";
import {
  DISRUPTIVE_MEASURES,
  EPC_BANDS,
  findExactDuplicate,
  SCENARIO_GOALS,
  SCENARIO_MEASURES,
  scenarioMeasuresList,
  type ScenarioMeasureKey,
} from "@/lib/scenarios/model";
import { BandChip, EPC_SOFT, GOAL_DESCRIPTIONS, GOAL_SHORT_LABELS, GoalIcon, bandInk, bandTint, formatMoney } from "../ui";

interface ExistingScenario {
  id: string;
  name: string;
  housingType: string;
  goal: string;
  goalValue: string | null;
  budget: number | null;
  exclusions: string[];
  fabricFirst: boolean;
  modelled: boolean;
}

// Grouped presentation of SCENARIO_MEASURES (the backend MeasureType vocabulary)
const MEASURE_GROUPS: [string, ScenarioMeasureKey[]][] = [
  ["Insulation", ["internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation", "loft_insulation", "flat_roof_insulation", "sloping_ceiling_insulation", "suspended_floor_insulation", "solid_floor_insulation"]],
  ["Heating & hot water", ["gas_boiler_upgrade", "high_heat_retention_storage_heaters", "air_source_heat_pump", "secondary_heating_removal", "system_tune_up", "system_tune_up_zoned"]],
  ["Glazing & ventilation", ["double_glazing", "secondary_glazing", "mechanical_ventilation"]],
  ["Renewables & other", ["solar_pv", "low_energy_lighting"]],
];

const PRESETS: { label: string; hint: string; excl: ScenarioMeasureKey[] }[] = [
  { label: "No wet trades", hint: "Rules out plaster-and-screed work: wall and solid-floor insulation",
    excl: ["internal_wall_insulation", "external_wall_insulation", "solid_floor_insulation"] },
  { label: "Fabric only", hint: "Insulation and glazing only — no heating systems or renewables",
    excl: ["gas_boiler_upgrade", "high_heat_retention_storage_heaters", "air_source_heat_pump", "secondary_heating_removal", "system_tune_up", "system_tune_up_zoned", "solar_pv", "low_energy_lighting", "mechanical_ventilation"] },
  { label: "Low disruption", hint: "Excludes every measure marked as disruptive",
    excl: Object.keys(DISRUPTIVE_MEASURES) as ScenarioMeasureKey[] },
];

const fieldLabel =
  "mb-2 block font-manrope text-[11px] font-extrabold uppercase tracking-[.1em] text-gray-600";
const inputCls =
  "w-full rounded-xl border border-gray-200 bg-white px-3 py-2.5 text-sm outline-none transition focus:border-brandmidblue focus:shadow-[0_0_0_3px_rgba(57,67,183,.12)]";
const btn =
  "rounded-xl border border-gray-200 bg-white px-4 py-2 text-sm font-semibold text-brandblue transition hover:bg-gray-50";
const btnPrimary =
  "rounded-xl px-4 py-2.5 text-sm font-semibold text-white shadow-[0_2px_10px_rgba(57,67,183,.35)] transition hover:shadow-[0_4px_16px_rgba(57,67,183,.45)]";
const gradPrimary = { background: "linear-gradient(135deg,#3943b7,#2d348f)" };

export function NewScenarioJourney({
  portfolioId,
  existing,
  defaultHousing,
  template,
}: {
  portfolioId: string;
  existing: ExistingScenario[];
  defaultHousing: string;
  template: ExistingScenario | null;
}) {
  const router = useRouter();
  const [step, setStep] = useState(1);
  const [name, setName] = useState("");
  const [housing, setHousing] = useState(template?.housingType ?? defaultHousing);
  const [goal, setGoal] = useState(template?.goal ?? PORTFOLIO_GOALS.EPC);
  const [band, setBand] = useState<string | null>(template?.goalValue ?? null);
  const [budget, setBudget] = useState(template?.budget ? String(template.budget) : "");
  const [excluded, setExcluded] = useState<Set<string>>(new Set(template?.exclusions ?? []));
  const [fabricFirst, setFabricFirst] = useState(template?.fabricFirst ?? false);
  const [errors, setErrors] = useState<{ name?: string; band?: string; excl?: string }>({});

  const isEpc = goal === PORTFOLIO_GOALS.EPC;
  const budgetNumber = budget ? Number(budget) : null;

  const save = useMutation({
    mutationFn: async () => {
      const res = await fetch(`/api/portfolio/${portfolioId}/scenarios`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          name: name.trim(),
          housingType: housing,
          goal,
          goalValue: isEpc ? band : null,
          budgetPerProperty: budgetNumber,
          exclusions: [...excluded],
          fabricFirst,
        }),
      });
      if (!res.ok) throw new Error((await res.json()).error ?? "Save failed");
    },
    onSuccess: () => {
      router.push(`/portfolio/${portfolioId}/scenarios`);
      // The scenarios list is server-rendered; without a refresh the client
      // router cache serves the pre-save page ("No scenarios yet").
      router.refresh();
    },
    onError: (e: Error) => setErrors({ excl: e.message }),
  });

  const suggestion = (() => {
    if (name) return null;
    if (!isEpc) {
      return GOAL_SHORT_LABELS[goal] + (budgetNumber ? ` — ${formatMoney(budgetNumber)} cap` : "");
    }
    if (!band) return null;
    let s = `Reach EPC ${band}`;
    const ex = [...excluded];
    if (ex.length === 1) s += ` — excl. ${SCENARIO_MEASURES[ex[0] as ScenarioMeasureKey] ?? ex[0]}`;
    else if (ex.length > 1) s += ` — ${ex.length} exclusions`;
    if (budgetNumber) s += ` — ${formatMoney(budgetNumber)}/property`;
    return s;
  })();

  const duplicate =
    step === 3
      ? findExactDuplicate(
          {
            housingType: housing,
            goal,
            goalValue: isEpc ? band : null,
            budgetPerProperty: budgetNumber,
            exclusions: [...excluded],
            fabricFirst,
          },
          existing.map((s) => ({
            id: BigInt(s.id),
            name: s.name,
            housingType: s.housingType,
            goal: s.goal,
            goalValue: s.goalValue,
            budget: s.budget,
            exclusions: s.exclusions.length ? `{${s.exclusions.join(",")}}` : null,
            fabricFirst: s.fabricFirst,
          })),
        )
      : null;
  const duplicateView = duplicate
    ? existing.find((s) => s.id === String(duplicate.id))
    : null;

  const next = () => {
    if (step === 1) {
      const e: typeof errors = {};
      if (!name.trim()) e.name = "Give the scenario a name before continuing.";
      if (isEpc && !band) e.band = "Pick the band every property should reach.";
      setErrors(e);
      if (Object.keys(e).length) return;
    }
    if (step === 2 && excluded.size === scenarioMeasuresList.length) {
      setErrors({ excl: "You've excluded every measure — the engine would have nothing to work with. Allow at least one." });
      return;
    }
    setErrors({});
    setStep(step + 1);
  };

  const rail = [
    [1, "Goal"],
    [2, "Measures"],
    [3, "Review"],
  ] as const;

  return (
    <div className="max-w-8xl mx-auto px-6 pb-16 pt-6">
      <Link
        href={`/portfolio/${portfolioId}/scenarios`}
        className="mb-4 inline-flex items-center gap-1.5 text-[13px] text-gray-600 hover:text-brandblue"
      >
        ← All scenarios
      </Link>
      <div className="mb-6">
        <span className="font-manrope text-[11px] font-extrabold uppercase tracking-[.14em] text-brandmidblue">
          New scenario
        </span>
        <h2 className="mt-0.5 font-manrope text-2xl font-extrabold tracking-tight text-brandblue">
          Create a scenario
        </h2>
        <div
          className="mt-3 h-[3px] max-w-[280px] rounded-full"
          style={{ background: "linear-gradient(to right,#14163d 0%,#3943b7 34%,rgba(57,67,183,0) 90%)" }}
        />
      </div>

      <div className="grid max-w-[1000px] grid-cols-1 gap-8 md:grid-cols-[225px_minmax(0,1fr)]">
        <div className="sticky top-5 flex flex-col self-start">
          {rail.map(([n, label]) => (
            <div
              key={n}
              className={`flex items-center gap-3 rounded-xl px-3 py-2.5 font-medium ${
                step === n
                  ? "bg-brandlightblue font-semibold text-brandblue"
                  : step > n
                    ? "text-gray-600"
                    : "text-gray-400"
              }`}
            >
              <span
                className={`inline-flex h-[25px] w-[25px] flex-none items-center justify-center rounded-full border-[1.5px] font-manrope text-xs font-extrabold ${
                  step > n
                    ? "border-transparent text-white"
                    : step === n
                      ? "border-brandmidblue bg-white text-brandmidblue"
                      : "border-gray-200 bg-white"
                }`}
                style={step > n ? gradPrimary : undefined}
              >
                {step > n ? "✓" : n}
              </span>
              {label}
            </div>
          ))}
        </div>

        <div className="relative overflow-hidden rounded-2xl border border-gray-100 bg-white p-7 shadow-sm">
          {step === 1 && isEpc && band && (
            <span
              aria-hidden
              className="pointer-events-none absolute -right-14 -top-14 h-[170px] w-[170px] rounded-full opacity-[.14] blur-[46px]"
              style={{ background: EPC_SOFT[band] }}
            />
          )}

          {step === 1 && (
            <div className="relative">
              <h3 className="font-manrope text-lg font-extrabold text-brandblue">
                What should this scenario achieve?
              </h3>
              <p className="mb-6 mt-1 max-w-[60ch] text-sm text-gray-600">
                Give it a name your team will recognise, and set the goal the
                engine optimises for.
              </p>
              <div className="mb-5">
                <label className={fieldLabel} htmlFor="f-name">Scenario name</label>
                <input
                  id="f-name"
                  className={`${inputCls} max-w-[440px]`}
                  value={name}
                  placeholder="e.g. Reach EPC C — no wet trades"
                  onChange={(e) => setName(e.target.value)}
                />
                {suggestion && (
                  <button
                    className="mt-2 inline-block rounded-full border border-dashed border-brandmidblue bg-brandlightblue px-3 py-1 text-xs font-semibold text-brandmidblue"
                    onClick={() => setName(suggestion)}
                  >
                    Use “{suggestion}”
                  </button>
                )}
                {errors.name && <div className="mt-2 text-[13px] text-red-800">{errors.name}</div>}
              </div>
              <div className="mb-5">
                <label className={fieldLabel}>Housing type</label>
                <div className="inline-flex overflow-hidden rounded-xl border border-gray-200 bg-white" role="group">
                  {["Social", "Private"].map((h) => (
                    <button
                      key={h}
                      aria-pressed={housing === h}
                      className={`px-5 py-2 text-sm font-semibold ${
                        housing === h ? "text-white" : "text-gray-600"
                      } ${h === "Private" ? "border-l border-gray-200" : ""}`}
                      style={housing === h ? gradPrimary : undefined}
                      onClick={() => setHousing(h)}
                    >
                      {h}
                    </button>
                  ))}
                </div>
                <div className="mt-2 text-xs text-gray-400">
                  Pre-filled from this portfolio&apos;s previous scenarios. Housing
                  type changes which funding applies.
                </div>
              </div>
              <div className="mb-5">
                <label className={fieldLabel}>Goal</label>
                <div className="grid grid-cols-[repeat(auto-fill,minmax(215px,1fr))] gap-2.5">
                  {SCENARIO_GOALS.map((g) => (
                    <button
                      key={g}
                      aria-pressed={goal === g}
                      className={`flex flex-col gap-1 rounded-xl border p-3.5 text-left transition ${
                        goal === g
                          ? "border-brandmidblue bg-brandlightblue shadow-[0_0_0_1px_#3943b7]"
                          : "border-gray-200 bg-white hover:border-gray-400"
                      }`}
                      onClick={() => setGoal(g)}
                    >
                      <b className="font-manrope text-sm font-bold text-brandblue">
                        {GOAL_SHORT_LABELS[g]}
                      </b>
                      <span className="text-xs leading-relaxed text-gray-600">
                        {GOAL_DESCRIPTIONS[g]}
                      </span>
                    </button>
                  ))}
                </div>
              </div>
              {isEpc && (
                <div className="mb-5 pb-5">
                  <label className={fieldLabel}>Target band</label>
                  <div className="flex max-w-[480px] gap-1.5">
                    {EPC_BANDS.map((b) => (
                      <button
                        key={b}
                        aria-pressed={band === b}
                        className="relative h-[52px] rounded-xl border-2 font-manrope text-lg font-extrabold transition-all"
                        style={
                          band === b
                            ? {
                                background: EPC_SOFT[b],
                                color: bandInk(b),
                                flexGrow: 1.7,
                                transform: "translateY(-3px)",
                                borderColor: "#14163d",
                                boxShadow: "inset 0 -12px 16px rgba(0,0,0,.10)",
                              }
                            : {
                                background: bandTint(b),
                                color: "#3f4757",
                                flexGrow: 1,
                                borderColor: "transparent",
                              }
                        }
                        onClick={() => setBand(b)}
                      >
                        {b}
                        {band === b && (
                          <span className="absolute -bottom-[21px] left-1/2 -translate-x-1/2 text-[9px] font-extrabold uppercase tracking-[.14em] text-gray-600">
                            target
                          </span>
                        )}
                      </button>
                    ))}
                  </div>
                  {errors.band && <div className="mt-2 text-[13px] text-red-800">{errors.band}</div>}
                </div>
              )}
              <div>
                <label className={fieldLabel} htmlFor="f-budget">
                  Budget per property (£){isEpc ? " — optional" : ""}
                </label>
                <input
                  id="f-budget"
                  type="number"
                  min={0}
                  step={100}
                  className={`${inputCls} max-w-[220px]`}
                  value={budget}
                  placeholder="No cap"
                  onChange={(e) => setBudget(e.target.value)}
                />
                <div className="mt-2 text-xs text-gray-400">
                  Leave empty for no cap — the engine recommends the maximum
                  interventions.
                </div>
              </div>
            </div>
          )}

          {step === 2 && (
            <div className="relative">
              <h3 className="font-manrope text-lg font-extrabold text-brandblue">
                Which measures are on the table?
              </h3>
              <p className="mb-2 mt-1 max-w-[60ch] text-sm text-gray-600">
                Everything is allowed unless you rule it out. Click a measure to
                exclude it — the engine chooses the best mix from whatever
                remains.
              </p>
              <p className="mb-5 max-w-[60ch] text-[13px] text-gray-400">
                Measures marked{" "}
                <span className="font-manrope text-[9px] font-extrabold uppercase tracking-[.08em] text-amber-600">
                  disruptive
                </span>{" "}
                involve major internal works — landlords often exclude them.
                Hover one to see why.
              </p>
              <div className="mb-3 flex flex-wrap items-center gap-2">
                <span className="mr-1 font-manrope text-[11px] font-extrabold uppercase tracking-[.1em] text-gray-400">
                  Quick starts
                </span>
                {PRESETS.map((p) => (
                  <button
                    key={p.label}
                    title={p.hint}
                    className={`${btn} !rounded-full !px-3.5 !py-1 !text-xs`}
                    onClick={() => setExcluded(new Set(p.excl))}
                  >
                    {p.label}
                  </button>
                ))}
              </div>
              <div className="mb-5 flex items-center gap-2.5">
                <button className={btn} onClick={() => setExcluded(new Set(scenarioMeasuresList))}>
                  Exclude all
                </button>
                <button className={btn} onClick={() => setExcluded(new Set())}>
                  Allow all
                </button>
                <span className="ml-auto text-[13px] tabular-nums text-gray-600">
                  {excluded.size === 0
                    ? `All ${scenarioMeasuresList.length} measures allowed`
                    : `${excluded.size} excluded · ${scenarioMeasuresList.length - excluded.size} allowed`}
                </span>
              </div>
              {MEASURE_GROUPS.map(([group, keys]) => (
                <div key={group} className="mb-5">
                  <span className="mb-2 block font-manrope text-[11px] font-extrabold uppercase tracking-[.1em] text-gray-400">
                    {group}
                  </span>
                  <div className="flex flex-wrap gap-2">
                    {keys.map((k) => {
                      const off = excluded.has(k);
                      const disruptiveReason = DISRUPTIVE_MEASURES[k];
                      return (
                        <button
                          key={k}
                          aria-pressed={off}
                          title={
                            disruptiveReason
                              ? `Disruptive: ${disruptiveReason}. Landlords often exclude this.`
                              : undefined
                          }
                          className={`inline-flex items-center gap-2 rounded-full border px-3.5 py-1.5 text-[13px] transition ${
                            off
                              ? "border-gray-200 bg-gray-100 text-gray-400 line-through hover:border-gray-300"
                              : disruptiveReason
                                ? "border-amber-200 bg-white text-brandblue hover:border-amber-400"
                                : "border-gray-200 bg-white text-brandblue hover:border-gray-400"
                          }`}
                          onClick={() =>
                            setExcluded((prev) => {
                              const nextSet = new Set(prev);
                              if (nextSet.has(k)) nextSet.delete(k);
                              else nextSet.add(k);
                              return nextSet;
                            })
                          }
                        >
                          <span className={off ? "text-gray-400" : "font-bold text-brandmidblue"}>
                            {off ? "✕" : "✓"}
                          </span>
                          {SCENARIO_MEASURES[k]}
                          {disruptiveReason && !off && (
                            <span className="font-manrope text-[9px] font-extrabold uppercase tracking-[.08em] text-amber-600">
                              disruptive
                            </span>
                          )}
                        </button>
                      );
                    })}
                  </div>
                </div>
              ))}
              <label
                className={`mt-2 flex cursor-pointer items-start gap-3.5 rounded-xl border p-4 transition ${
                  fabricFirst
                    ? "border-emerald-300 bg-emerald-50/70 shadow-[0_0_0_3px_rgba(16,185,129,.12)]"
                    : "border-gray-200 bg-white hover:border-emerald-200 hover:bg-emerald-50/30"
                }`}
              >
                <span
                  aria-hidden
                  className={`mt-0.5 inline-flex h-9 w-9 flex-none items-center justify-center rounded-lg transition ${
                    fabricFirst ? "bg-emerald-500 text-white" : "bg-emerald-50 text-emerald-500"
                  }`}
                >
                  <svg
                    width="18"
                    height="18"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <path d="M12 2 2 7l10 5 10-5-10-5Z" />
                    <path d="m2 17 10 5 10-5" />
                    <path d="m2 12 10 5 10-5" />
                  </svg>
                </span>
                <span className="flex min-w-0 flex-col">
                  <span className="font-manrope text-[10px] font-extrabold uppercase tracking-[.12em] text-emerald-600">
                    Optimisation order
                  </span>
                  <span className="text-sm font-semibold text-brandblue">Fabric first</span>
                  <span className="mt-0.5 text-[13px] text-gray-500">
                    Insulation, glazing and ventilation are applied first; heating and
                    renewables are only considered if the target isn&apos;t met.
                  </span>
                </span>
                <input
                  type="checkbox"
                  checked={fabricFirst}
                  onChange={(e) => setFabricFirst(e.target.checked)}
                  className="mt-1 h-4 w-4 flex-none accent-emerald-600"
                />
              </label>
              {errors.excl && <div className="text-[13px] text-red-800">{errors.excl}</div>}
            </div>
          )}

          {step === 3 && (
            <div className="relative">
              <h3 className="font-manrope text-lg font-extrabold text-brandblue">
                Review and save
              </h3>
              <p className="mb-5 mt-1 max-w-[60ch] text-sm text-gray-600">
                Check the configuration — it can&apos;t be changed once saved (you
                can rename later). A different question is a new scenario.
              </p>
              {(() => {
                const allowedDisruptive = (
                  Object.keys(DISRUPTIVE_MEASURES) as ScenarioMeasureKey[]
                ).filter((k) => !excluded.has(k));
                return allowedDisruptive.length > 0 ? (
                  <div className="mb-5 max-w-[62ch] rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-[13px] text-amber-900">
                    This scenario still allows{" "}
                    <b>
                      {allowedDisruptive
                        .map((k) => SCENARIO_MEASURES[k])
                        .join(", ")}
                    </b>{" "}
                    — disruptive measure{allowedDisruptive.length > 1 ? "s" : ""}{" "}
                    landlords often exclude. Go back a step if you&apos;d rather
                    rule {allowedDisruptive.length > 1 ? "them" : "it"} out.
                  </div>
                ) : null;
              })()}
              {duplicateView && (
                <div
                  role="alert"
                  className="mb-5 flex flex-wrap items-center justify-between gap-4 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-[13px] text-amber-900"
                >
                  <div className="max-w-[52ch]">
                    <b>Identical to “{duplicateView.name}”</b> — same goal,
                    housing type, budget and exclusions.{" "}
                    {duplicateView.modelled
                      ? "It has already been modelled; running this again would produce the same plans."
                      : "It hasn't been modelled yet — you may just want that one."}
                  </div>
                  <Link
                    href={`/portfolio/${portfolioId}/scenarios/${duplicateView.id}`}
                    className={`${btn} flex-none`}
                  >
                    View “{duplicateView.name}”
                  </Link>
                </div>
              )}
              <div className="rounded-xl border border-gray-100 bg-white">
                {[
                  ["Name", <b key="n" className="font-semibold">{name.trim()}</b>],
                  [
                    "Goal",
                    <span key="g" className="flex items-center gap-2.5 font-semibold">
                      {isEpc && band ? <BandChip band={band} size={28} /> : <GoalIcon size={28} />}
                      {isEpc ? `Bring every property to EPC ${band}` : `${GOAL_SHORT_LABELS[goal]} — as far as possible`}
                    </span>,
                  ],
                  ["Housing type", housing],
                  [
                    "Budget / property",
                    budgetNumber ? (
                      formatMoney(budgetNumber)
                    ) : (
                      <span key="b" className="text-gray-400">No cap — maximum interventions</span>
                    ),
                  ],
                  [
                    "Exclusions",
                    excluded.size === 0 ? (
                      <span key="e" className="text-gray-400">None — every measure is on the table</span>
                    ) : (
                      <span key="e" className="flex flex-wrap gap-1.5">
                        {[...excluded].sort().map((k) => (
                          <span
                            key={k}
                            className="rounded-full border border-red-100 bg-white px-3 py-0.5 text-[13px] text-red-800 line-through"
                          >
                            {SCENARIO_MEASURES[k as ScenarioMeasureKey] ?? k}
                          </span>
                        ))}
                      </span>
                    ),
                  ],
                  [
                    "Fabric first",
                    fabricFirst ? (
                      "On — fabric before heating & renewables"
                    ) : (
                      <span key="ff" className="text-gray-400">Off — measures considered together</span>
                    ),
                  ],
                ].map(([label, value]) => (
                  <div
                    key={label as string}
                    className="grid grid-cols-[190px_1fr] items-start gap-4 border-b border-gray-100 px-4.5 py-3.5 last:border-b-0 px-5"
                  >
                    <div className="pt-0.5 font-manrope text-[11px] font-extrabold uppercase tracking-[.1em] text-gray-400">
                      {label}
                    </div>
                    <div className="text-sm text-brandblue">{value}</div>
                  </div>
                ))}
              </div>
              {errors.excl && <div className="mt-3 text-[13px] text-red-800">{errors.excl}</div>}
            </div>
          )}

          <div className="relative mt-7 flex items-center justify-between border-t border-gray-100 pt-5">
            <button
              className={`px-2 py-2 text-sm font-semibold text-brandmidblue ${step === 1 ? "invisible" : ""}`}
              onClick={() => setStep(step - 1)}
            >
              ← Back
            </button>
            {step < 3 ? (
              <button className={btnPrimary} style={gradPrimary} onClick={next}>
                Continue →
              </button>
            ) : (
              <button
                className={btnPrimary}
                style={gradPrimary}
                disabled={save.isLoading}
                onClick={() => save.mutate()}
              >
                {save.isLoading ? "Saving…" : "Save scenario"}
              </button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}
