"use client";

/**
 * ConceptProgramForm — §7 «Концепция» unified program form (epic #1953).
 *
 * The SINGLE input surface for the section-7 concept engine. Replaces the torn
 * two-engine layout (live 3D massing + separate ConceptParamsForm) with ONE
 * coherent form whose primary control is «сколько корпусов строить». It builds a
 * single-type `building_program` item `{ section_type, floors, count }` — the
 * backend's `place_program` lays out EXACTLY `count` building footprints, so
 * «число корпусов» === the stepper value and scatter is structurally impossible
 * while the «уплотнить» toggle is OFF.
 *
 * Controlled: the parent owns nothing of the form's internal state; the form
 * keeps it locally and lifts a fully-resolved payload via `onSubmit`. The parent
 * maps that to `concept.mutate` (building_program when toggle OFF, omitted when
 * ON → explicit greedy max-FAR opt-in).
 *
 * Styling: inline styles + CSS var tokens only (Tailwind classes don't generate
 * in this bundle). Catalog (footprint / default floors / class) comes from
 * `useHouseTypes()` — the single source of truth, no frontend hardcode.
 */

import { useEffect, useMemo, useState } from "react";
import { Minus, Plus, Sparkles } from "lucide-react";

import { Section } from "@/components/analytics/Section";
import {
  DEVELOPMENT_TYPE_LABELS,
  HOUSING_CLASS_LABELS,
  useHouseTypes,
  type DevelopmentType,
  type HousingClass,
  type HouseTypeCatalogItem,
} from "@/lib/concept-api";

// ── Contract / UI bounds ──────────────────────────────────────────────────────

const CORPUSES_MIN = 1;
const CORPUSES_MAX = 12;
const CORPUSES_DEFAULT = 3;

const FLOORS_MIN = 1;
const FLOORS_MAX = 40;
const FLOORS_FALLBACK = 9;

const FLOOR_HEIGHT_MIN = 2.4;
const FLOOR_HEIGHT_MAX = 4.5;
const FLOOR_HEIGHT_DEFAULT = 3.0;

// Ручное пятно секции (м). Границы зеркалят backend BuildingProgramItem
// (footprint_w_m / footprint_d_m, ge=4 le=120).
const FOOTPRINT_MIN = 4;
const FOOTPRINT_MAX = 120;

// ── Public payload (lifted to the parent on submit) ───────────────────────────

/**
 * The fully-resolved form state the parent needs to call `concept.mutate`.
 * `densify` ON → the parent OMITS building_program (greedy max-FAR scatter is the
 * explicit opt-in); OFF → the parent sends a single-type program item with
 * `count = corpuses`. `floor_height_m` is PR-A visual-only (drives the height
 * readout, NOT sent to the backend — ТЭП is computed from floors).
 */
export interface ConceptProgramFormState {
  /** «Сколько корпусов строить» → building_program item `count` (toggle OFF). */
  corpuses: number;
  /** Этажность → building_program item `floors` + scalar `target_floors`. */
  floors: number;
  /** Высота этажа, м — visual only (PR-A); drives the height readout. */
  floor_height_m: number;
  /** Каталожный тип секции → building_program item `section_type`. */
  section_type: string;
  /** Пятно секции (ширина, м) → building_program item `footprint_w_m`. */
  footprint_w_m: number;
  /** Пятно секции (глубина, м) → building_program item `footprint_d_m`. */
  footprint_d_m: number;
  housing_class: HousingClass;
  development_type: DevelopmentType;
  land_cost_rub: number | null;
  /** «Уплотнить до максимума» → parent omits building_program (greedy) when true. */
  densify: boolean;
}

interface SeededDefaults {
  housing_class: HousingClass;
  development_type: DevelopmentType;
  land_cost_rub: number | null;
}

interface Props {
  parcelAreaSqm: number;
  seeded: SeededDefaults;
  hasPolygon: boolean;
  isPending: boolean;
  onSubmit: (state: ConceptProgramFormState) => void;
}

// ── Shared style tokens (match ConceptParamsForm patterns) ────────────────────

const fieldLabelStyle: React.CSSProperties = {
  display: "block",
  fontSize: 12,
  fontWeight: 500,
  textTransform: "uppercase",
  letterSpacing: "0.04em",
  color: "var(--fg-secondary)",
  marginBottom: 6,
};

const controlStyle: React.CSSProperties = {
  width: "100%",
  padding: "8px 12px",
  fontSize: 14,
  border: "1px solid var(--border-strong)",
  borderRadius: 8,
  outline: "none",
  background: "var(--bg-card)",
  color: "var(--fg-primary)",
};

const helperStyle: React.CSSProperties = {
  margin: "4px 0 0",
  fontSize: 11,
  color: "var(--fg-tertiary)",
};

const tabularStyle: React.CSSProperties = {
  fontVariantNumeric: "tabular-nums",
};

// ── Formatters (ru microcopy) ─────────────────────────────────────────────────

const nf0 = new Intl.NumberFormat("ru-RU", { maximumFractionDigits: 0 });
const ha = (sqm: number) =>
  (sqm / 10_000).toLocaleString("ru-RU", { maximumFractionDigits: 2 });

function clampInt(
  raw: number,
  min: number,
  max: number,
  fallback: number,
): number {
  if (!Number.isFinite(raw)) return fallback;
  return Math.min(max, Math.max(min, Math.round(raw)));
}

function clampFloat(raw: number, min: number, max: number): number | null {
  if (!Number.isFinite(raw)) return null;
  return Math.min(max, Math.max(min, raw));
}

/** First comfort-class catalog type (else first catalog entry, else null). */
function pickDefaultType(
  catalog: HouseTypeCatalogItem[],
): HouseTypeCatalogItem | null {
  if (catalog.length === 0) return null;
  return catalog.find((ht) => ht.housing_class === "comfort") ?? catalog[0];
}

// ── ConceptProgramForm ────────────────────────────────────────────────────────

export function ConceptProgramForm({
  parcelAreaSqm,
  seeded,
  hasPolygon,
  isPending,
  onSubmit,
}: Props) {
  const houseTypes = useHouseTypes();
  const catalog = useMemo(() => houseTypes.data ?? [], [houseTypes.data]);

  const [corpuses, setCorpuses] = useState<number>(CORPUSES_DEFAULT);
  const [floors, setFloors] = useState<number>(FLOORS_FALLBACK);
  const [floorHeight, setFloorHeight] = useState<number>(FLOOR_HEIGHT_DEFAULT);
  const [sectionType, setSectionType] = useState<string>("");
  // Ручное пятно: null → используем габариты каталога по типу секции; число →
  // пользователь «вписал» свой габарит (override). Сбрасывается в null при смене
  // типа (новый тип несёт свои каталожные габариты).
  const [footprintW, setFootprintW] = useState<number | null>(null);
  const [footprintD, setFootprintD] = useState<number | null>(null);
  const [housingClass, setHousingClass] = useState<HousingClass>(
    seeded.housing_class,
  );
  const [developmentType, setDevelopmentType] = useState<DevelopmentType>(
    seeded.development_type,
  );
  const [landCostRub, setLandCostRub] = useState<number | null>(
    seeded.land_cost_rub,
  );
  const [densify, setDensify] = useState<boolean>(false);

  // Seed the section type + floors from the catalog once it loads. Only seeds
  // while the type is still unset so manual edits are never clobbered on refetch.
  useEffect(() => {
    if (sectionType !== "" || catalog.length === 0) return;
    const def = pickDefaultType(catalog);
    if (!def) return;
    setSectionType(def.section_type);
    setFloors(def.default_floors > 0 ? def.default_floors : FLOORS_FALLBACK);
  }, [catalog, sectionType]);

  const selectedType = useMemo<HouseTypeCatalogItem | null>(
    () => catalog.find((ht) => ht.section_type === sectionType) ?? null,
    [catalog, sectionType],
  );

  // Эффективное пятно секции: ручной override (footprintW/D) или каталог по типу.
  const effFootprintW = footprintW ?? selectedType?.footprint_w_m ?? null;
  const effFootprintD = footprintD ?? selectedType?.footprint_d_m ?? null;

  // ── Derived read-only readouts (closes «видеть характеристики» complaint) ──
  const buildingHeightM = floors * floorHeight;
  const footprintSqm =
    effFootprintW != null && effFootprintD != null
      ? effFootprintW * effFootprintD
      : null;
  const totalFootprintSqm =
    footprintSqm != null ? corpuses * footprintSqm : null;
  const ksitEstimate =
    footprintSqm != null && parcelAreaSqm > 0
      ? (corpuses * footprintSqm * floors) / parcelAreaSqm
      : null;

  const catalogReady = houseTypes.isSuccess && catalog.length > 0;
  const disabled = !hasPolygon || isPending || !catalogReady;

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (disabled || sectionType === "") return;
    if (effFootprintW == null || effFootprintD == null) return;
    onSubmit({
      corpuses,
      floors,
      floor_height_m: floorHeight,
      section_type: sectionType,
      footprint_w_m: effFootprintW,
      footprint_d_m: effFootprintD,
      housing_class: housingClass,
      development_type: developmentType,
      land_cost_rub: landCostRub,
      densify,
    });
  }

  function handleTypeChange(nextType: string) {
    setSectionType(nextType);
    const ht = catalog.find((c) => c.section_type === nextType);
    if (ht && ht.default_floors > 0) setFloors(ht.default_floors);
    // Смена типа сбрасывает ручной override пятна на каталожные габариты нового типа.
    setFootprintW(null);
    setFootprintD(null);
  }

  return (
    <Section
      title="Программа застройки"
      subtitle="Задайте число корпусов, этажность и тип секции — движок разложит ровно эту программу на участке и посчитает ТЭП и финмодель по геометрии."
    >
      <form onSubmit={handleSubmit} style={{ display: "grid", gap: 16 }}>
        {/* 1. «Сколько корпусов строить» — первый и самый крупный блок. */}
        <div
          style={{
            border: "1px solid var(--accent-soft)",
            borderRadius: 12,
            padding: 16,
            background: "var(--accent-soft)",
            opacity: densify ? 0.55 : 1,
          }}
        >
          <span style={{ ...fieldLabelStyle, color: "var(--accent)" }}>
            Сколько корпусов строить
          </span>
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: 12,
              marginTop: 4,
            }}
          >
            <button
              type="button"
              aria-label="Убавить число корпусов"
              disabled={densify || corpuses <= CORPUSES_MIN}
              onClick={() => setCorpuses((n) => Math.max(CORPUSES_MIN, n - 1))}
              style={stepperButtonStyle(densify || corpuses <= CORPUSES_MIN)}
            >
              <Minus size={20} strokeWidth={1.5} />
            </button>
            <div
              aria-live="polite"
              style={{
                minWidth: 56,
                height: 44,
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                fontSize: 28,
                fontWeight: 600,
                color: "var(--fg-primary)",
                ...tabularStyle,
              }}
            >
              {corpuses}
            </div>
            <button
              type="button"
              aria-label="Прибавить число корпусов"
              disabled={densify || corpuses >= CORPUSES_MAX}
              onClick={() => setCorpuses((n) => Math.min(CORPUSES_MAX, n + 1))}
              style={stepperButtonStyle(densify || corpuses >= CORPUSES_MAX)}
            >
              <Plus size={20} strokeWidth={1.5} />
            </button>
            <input
              type="range"
              min={CORPUSES_MIN}
              max={CORPUSES_MAX}
              step={1}
              value={corpuses}
              disabled={densify}
              aria-label="Число корпусов на участке"
              onChange={(e) =>
                setCorpuses(
                  clampInt(
                    Number(e.target.value),
                    CORPUSES_MIN,
                    CORPUSES_MAX,
                    CORPUSES_DEFAULT,
                  ),
                )
              }
              style={{
                flex: 1,
                accentColor: "var(--accent)",
                cursor: "pointer",
              }}
            />
          </div>
          <p style={{ ...helperStyle, color: "var(--fg-secondary)" }}>
            {densify
              ? "Число корпусов подбирает движок."
              : `корпусов на участке ≈ ${ha(parcelAreaSqm)} га`}
          </p>
        </div>

        {/* 2 + readout. Этажность + высота корпуса. */}
        <div>
          <label htmlFor="cpf-floors" style={fieldLabelStyle}>
            Этажность
          </label>
          <input
            id="cpf-floors"
            type="number"
            min={FLOORS_MIN}
            max={FLOORS_MAX}
            value={floors}
            onChange={(e) =>
              setFloors(
                clampInt(
                  Number(e.target.value),
                  FLOORS_MIN,
                  FLOORS_MAX,
                  FLOORS_FALLBACK,
                ),
              )
            }
            style={controlStyle}
          />
          <p style={helperStyle}>
            Высота корпуса ≈{" "}
            <span style={tabularStyle}>{buildingHeightM.toFixed(1)}</span> м (от
            1 до 40 этажей).
          </p>
        </div>

        {/* 3. Высота этажа — PR-A visual only. */}
        <div>
          <label htmlFor="cpf-floor-height" style={fieldLabelStyle}>
            Высота этажа, м
          </label>
          <input
            id="cpf-floor-height"
            type="number"
            step="any"
            min={FLOOR_HEIGHT_MIN}
            max={FLOOR_HEIGHT_MAX}
            value={floorHeight}
            onChange={(e) => {
              const next = clampFloat(
                Number(e.target.value),
                FLOOR_HEIGHT_MIN,
                FLOOR_HEIGHT_MAX,
              );
              if (next != null) setFloorHeight(next);
            }}
            style={controlStyle}
          />
          <p style={helperStyle}>
            Справочно — ТЭП считается от этажности, а не от высоты этажа.
          </p>
        </div>

        {/* 4. Тип секции. */}
        <div>
          <label htmlFor="cpf-section-type" style={fieldLabelStyle}>
            Тип секции
          </label>
          <select
            id="cpf-section-type"
            value={sectionType}
            disabled={!catalogReady}
            onChange={(e) => handleTypeChange(e.target.value)}
            style={controlStyle}
          >
            {!catalogReady && <option value="">Загрузка каталога…</option>}
            {catalog.map((opt) => (
              <option key={opt.section_type} value={opt.section_type}>
                {opt.label_ru}
              </option>
            ))}
          </select>
          <p style={helperStyle}>
            Габариты пятна по умолчанию — из типа секции; ниже можно вписать
            свои.
          </p>
        </div>

        {/* 4b. Пятно секции — редактируемое (ширина × глубина). */}
        <div>
          <span style={fieldLabelStyle}>
            Пятно секции, м (ширина × глубина)
          </span>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <input
              type="number"
              aria-label="Ширина пятна секции, м"
              min={FOOTPRINT_MIN}
              max={FOOTPRINT_MAX}
              step="any"
              value={effFootprintW ?? ""}
              disabled={!catalogReady}
              onChange={(e) =>
                // Пусто → null (вернуться к каталожным габаритам), иначе clamp.
                setFootprintW(
                  e.target.value.trim() === ""
                    ? null
                    : clampFloat(
                        Number(e.target.value),
                        FOOTPRINT_MIN,
                        FOOTPRINT_MAX,
                      ),
                )
              }
              style={{ ...controlStyle, flex: 1 }}
            />
            <span style={{ color: "var(--fg-tertiary)", fontSize: 14 }}>×</span>
            <input
              type="number"
              aria-label="Глубина пятна секции, м"
              min={FOOTPRINT_MIN}
              max={FOOTPRINT_MAX}
              step="any"
              value={effFootprintD ?? ""}
              disabled={!catalogReady}
              onChange={(e) =>
                // Пусто → null (вернуться к каталожным габаритам), иначе clamp.
                setFootprintD(
                  e.target.value.trim() === ""
                    ? null
                    : clampFloat(
                        Number(e.target.value),
                        FOOTPRINT_MIN,
                        FOOTPRINT_MAX,
                      ),
                )
              }
              style={{ ...controlStyle, flex: 1 }}
            />
          </div>
          {footprintSqm != null && (
            <p style={helperStyle}>
              ≈ <span style={tabularStyle}>{nf0.format(footprintSqm)}</span> м²
              на секцию
              {footprintW == null && footprintD == null ? " (из типа)" : ""}.
            </p>
          )}
        </div>

        {/* 5. Класс жилья. */}
        <div>
          <label htmlFor="cpf-housing-class" style={fieldLabelStyle}>
            Класс жилья
          </label>
          <select
            id="cpf-housing-class"
            value={housingClass}
            onChange={(e) => setHousingClass(e.target.value as HousingClass)}
            style={controlStyle}
          >
            {(Object.keys(HOUSING_CLASS_LABELS) as HousingClass[]).map(
              (key) => (
                <option key={key} value={key}>
                  {HOUSING_CLASS_LABELS[key]}
                </option>
              ),
            )}
          </select>
        </div>

        {/* 6. Тип застройки. */}
        <div>
          <label htmlFor="cpf-dev-type" style={fieldLabelStyle}>
            Тип застройки
          </label>
          <select
            id="cpf-dev-type"
            value={developmentType}
            onChange={(e) =>
              setDevelopmentType(e.target.value as DevelopmentType)
            }
            style={controlStyle}
          >
            {(Object.keys(DEVELOPMENT_TYPE_LABELS) as DevelopmentType[]).map(
              (key) => (
                <option key={key} value={key}>
                  {DEVELOPMENT_TYPE_LABELS[key]}
                </option>
              ),
            )}
          </select>
          <p style={helperStyle}>Влияет на график СМР и DCF.</p>
        </div>

        {/* 7. Стоимость участка. */}
        <div>
          <label htmlFor="cpf-land-cost" style={fieldLabelStyle}>
            Стоимость участка, ₽
          </label>
          <input
            id="cpf-land-cost"
            type="number"
            min={0}
            // step="any" — иначе сид из кадастровой стоимости (не кратной шагу,
            // напр. 74 766.08 ₽) даёт HTML5 stepMismatch → форма :invalid →
            // браузер молча блокирует submit и кнопка «Рассчитать» не работает.
            step="any"
            value={landCostRub ?? ""}
            placeholder="Необязательно"
            onChange={(e) => {
              const raw = e.target.value.trim();
              if (raw === "") {
                setLandCostRub(null);
                return;
              }
              const value = Number(raw);
              setLandCostRub(
                Number.isFinite(value) && value >= 0 ? value : null,
              );
            }}
            style={controlStyle}
          />
          <p style={helperStyle}>Учитывается в финмодели как часть затрат.</p>
        </div>

        {/* Σ пятно застройки + ориентир КСИТ — только при выключенном уплотнении. */}
        {!densify && (totalFootprintSqm != null || ksitEstimate != null) && (
          <div
            style={{
              border: "1px solid var(--border-card)",
              borderRadius: 12,
              padding: 12,
              background: "var(--bg-card-alt)",
              display: "grid",
              gap: 4,
            }}
          >
            {totalFootprintSqm != null && (
              <div style={{ fontSize: 13, color: "var(--fg-secondary)" }}>
                Σ пятно застройки ≈{" "}
                <span style={{ ...tabularStyle, color: "var(--fg-primary)" }}>
                  {nf0.format(totalFootprintSqm)}
                </span>{" "}
                м² ({corpuses} × {nf0.format(footprintSqm ?? 0)} м²)
              </div>
            )}
            {ksitEstimate != null && (
              <div style={{ fontSize: 13, color: "var(--fg-secondary)" }}>
                Ориентир КСИТ ≈{" "}
                <span style={{ ...tabularStyle, color: "var(--fg-primary)" }}>
                  {ksitEstimate.toFixed(2)}
                </span>{" "}
                (корпуса × пятно × этажность ÷ площадь участка)
              </div>
            )}
          </div>
        )}

        {/* 8. «Уплотнить до максимума» — toggle, default OFF. */}
        <div
          style={{
            display: "flex",
            alignItems: "flex-start",
            gap: 12,
            border: "1px solid var(--border-card)",
            borderRadius: 12,
            padding: 12,
          }}
        >
          <button
            type="button"
            role="switch"
            aria-checked={densify}
            aria-label="Уплотнить застройку до максимума по нормативу"
            onClick={() => setDensify((on) => !on)}
            style={{
              flexShrink: 0,
              width: 44,
              height: 24,
              borderRadius: 12,
              border: "none",
              padding: 2,
              cursor: "pointer",
              background: densify ? "var(--accent)" : "var(--border-strong)",
              transition: "background 150ms",
              display: "flex",
              alignItems: "center",
              justifyContent: densify ? "flex-end" : "flex-start",
            }}
          >
            <span
              style={{
                display: "block",
                width: 20,
                height: 20,
                borderRadius: "50%",
                background: "var(--bg-card)",
              }}
            />
          </button>
          <div>
            <div
              style={{
                fontSize: 14,
                fontWeight: 500,
                color: "var(--fg-primary)",
              }}
            >
              Уплотнить до максимума
            </div>
            <p style={{ ...helperStyle, marginTop: 2 }}>
              Движок сам забьёт участок по нормативу — плотное заполнение,
              ручной выбор числа корпусов отключается.
            </p>
          </div>
        </div>

        {/* 9. Primary CTA. */}
        <button
          type="submit"
          disabled={disabled}
          aria-label="Рассчитать концепцию застройки"
          style={{
            display: "inline-flex",
            alignItems: "center",
            justifyContent: "center",
            gap: 8,
            padding: "10px 18px",
            height: 44,
            background: disabled ? "var(--bg-card-alt)" : "var(--accent)",
            color: disabled ? "var(--fg-tertiary)" : "#fff",
            border: disabled ? "1px solid var(--border-card)" : "none",
            borderRadius: 8,
            fontSize: 14,
            fontWeight: 600,
            cursor: disabled ? "not-allowed" : "pointer",
            transition: "opacity 150ms",
          }}
        >
          <Sparkles size={16} strokeWidth={1.5} />
          {isPending ? "Расчёт концепции…" : "Рассчитать концепцию"}
        </button>

        {!hasPolygon && (
          <p style={{ margin: 0, fontSize: 12, color: "var(--fg-tertiary)" }}>
            Геометрия участка недоступна — концепцию построить нельзя.
          </p>
        )}
        {houseTypes.isError && (
          <p
            style={{ margin: 0, fontSize: 12, color: "var(--danger)" }}
            role="alert"
          >
            Не удалось загрузить каталог типовых домов:{" "}
            {houseTypes.error.message}
          </p>
        )}
      </form>
    </Section>
  );
}

// ── Stepper button style ───────────────────────────────────────────────────────

function stepperButtonStyle(isDisabled: boolean): React.CSSProperties {
  return {
    display: "inline-flex",
    alignItems: "center",
    justifyContent: "center",
    width: 44,
    height: 44,
    flexShrink: 0,
    borderRadius: 8,
    border: "1px solid var(--border-strong)",
    background: "var(--bg-card)",
    color: isDisabled ? "var(--fg-tertiary)" : "var(--fg-primary)",
    cursor: isDisabled ? "not-allowed" : "pointer",
  };
}
