"use client";

import { useCallback, useRef, useState } from "react";

import { SectionLabel } from "@/components/ui/SectionLabel";
import {
  POI_CATEGORIES,
  POI_DEFAULT_WEIGHTS,
  POI_LABELS,
  POI_WEIGHT_MAX,
  POI_WEIGHT_MIN,
  useCreateProfile,
  useWeightProfiles,
  type PoiCategoryKey,
  type WeightProfile,
} from "@/lib/api/weightProfiles";

// ── Props ─────────────────────────────────────────────────────────────────────

interface Props {
  /** Current effective weights for the analyze call. */
  currentWeights: Record<PoiCategoryKey, number>;
  /**
   * Called when user clicks "Применить".
   * @param weights - New weights.
   * @param profileId - The saved profile id if a named profile is active; null for custom/system.
   */
  onWeightsChange: (
    weights: Record<PoiCategoryKey, number>,
    profileId: number | null,
  ) => void;
  /**
   * If provided, enables save/load from DB.
   * Must be non-empty for CRUD functionality.
   */
  userId?: string;
  /** Admin token for CRUD API calls. */
  adminToken?: string;
}

// ── Helpers ───────────────────────────────────────────────────────────────────

function clamp(v: number): number {
  return Math.max(POI_WEIGHT_MIN, Math.min(POI_WEIGHT_MAX, v));
}

function weightsFromProfile(
  profile: WeightProfile,
): Record<PoiCategoryKey, number> {
  const result = { ...POI_DEFAULT_WEIGHTS };
  for (const cat of POI_CATEGORIES) {
    const v = profile.weights[cat];
    if (typeof v === "number") {
      result[cat] = clamp(v);
    }
  }
  return result;
}

function weightsEqual(
  a: Record<PoiCategoryKey, number>,
  b: Record<PoiCategoryKey, number>,
): boolean {
  return POI_CATEGORIES.every((c) => a[c] === b[c]);
}

// ── Component ─────────────────────────────────────────────────────────────────

export function WeightProfilePanel({
  currentWeights,
  onWeightsChange,
  userId,
  adminToken,
}: Props) {
  const [open, setOpen] = useState(false);

  // Local draft weights — editable before "Применить"
  const [draft, setDraft] = useState<Record<PoiCategoryKey, number>>(() => ({
    ...currentWeights,
  }));

  // Selected profile id (null = system defaults)
  const [selectedProfileId, setSelectedProfileId] = useState<number | null>(
    null,
  );

  // Save-dialog state
  const [showSaveDialog, setShowSaveDialog] = useState(false);
  const [saveName, setSaveName] = useState("");
  const [saveDefault, setSaveDefault] = useState(false);

  // Debounce timer ref
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  // Profiles query (only when userId + adminToken provided)
  const canUseCrud = !!userId && !!adminToken;
  const profilesQuery = useWeightProfiles(userId ?? "", adminToken ?? "");

  const createMutation = useCreateProfile(adminToken ?? "");

  // ── Handlers ────────────────────────────────────────────────────────────────

  function handleSliderChange(cat: PoiCategoryKey, raw: string) {
    const value = clamp(parseFloat(raw));
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      setDraft((prev) => ({ ...prev, [cat]: value }));
    }, 300);
    // Optimistic visual update (no debounce for the display value input itself)
    setDraft((prev) => ({ ...prev, [cat]: value }));
  }

  function handleReset() {
    setDraft({ ...POI_DEFAULT_WEIGHTS });
    setSelectedProfileId(null);
  }

  function handleLoadProfile(profile: WeightProfile) {
    setDraft(weightsFromProfile(profile));
    setSelectedProfileId(profile.id);
  }

  function handleApply() {
    onWeightsChange({ ...draft }, selectedProfileId);
  }

  const handleSaveProfile = useCallback(async () => {
    if (!canUseCrud || !userId || !adminToken) {
      setShowSaveDialog(false);
      return;
    }
    const name = saveName.trim();
    if (!name) return;
    try {
      await createMutation.mutateAsync({
        user_id: userId,
        profile_name: name,
        weights: { ...draft },
        is_default: saveDefault,
      });
      setShowSaveDialog(false);
      setSaveName("");
      setSaveDefault(false);
    } catch {
      // Error visible through createMutation.error
    }
  }, [
    canUseCrud,
    userId,
    adminToken,
    saveName,
    draft,
    saveDefault,
    createMutation,
  ]);

  // ── Derived ─────────────────────────────────────────────────────────────────

  const profiles: WeightProfile[] = profilesQuery.data ?? [];
  const isDirty = !weightsEqual(draft, currentWeights);
  const isDraftDifferentFromDefaults = !weightsEqual(
    draft,
    POI_DEFAULT_WEIGHTS,
  );

  // ── Styles ───────────────────────────────────────────────────────────────────

  const panelStyle: React.CSSProperties = {
    background: "#fff",
    border: "1px solid #e5e7eb",
    borderRadius: 10,
    overflow: "hidden",
  };

  const headerStyle: React.CSSProperties = {
    display: "flex",
    alignItems: "center",
    justifyContent: "space-between",
    padding: "10px 14px",
    cursor: "pointer",
    userSelect: "none",
    background: open ? "#f9fafb" : "#fff",
    borderBottom: open ? "1px solid #e5e7eb" : "none",
  };

  const bodyStyle: React.CSSProperties = {
    padding: "12px 14px",
    display: "flex",
    flexDirection: "column",
    gap: 10,
  };

  const sliderRowStyle: React.CSSProperties = {
    display: "grid",
    gridTemplateColumns: "130px 1fr 52px",
    alignItems: "center",
    gap: 8,
  };

  const valueChipStyle = (v: number): React.CSSProperties => ({
    fontSize: 12,
    fontWeight: 600,
    textAlign: "right",
    color: v < 0 ? "#ef4444" : v === 0 ? "#9ca3af" : "#16a34a",
    fontVariantNumeric: "tabular-nums",
  });

  const btnStyle = (
    variant: "primary" | "secondary" | "danger",
  ): React.CSSProperties => ({
    padding: "6px 12px",
    fontSize: 12,
    fontWeight: 600,
    borderRadius: 6,
    border: "none",
    cursor: "pointer",
    background:
      variant === "primary"
        ? "#1d4ed8"
        : variant === "danger"
          ? "#dc2626"
          : "#f3f4f6",
    color: variant === "secondary" ? "#374151" : "#fff",
  });

  // ── Render ──────────────────────────────────────────────────────────────────

  return (
    <div style={panelStyle}>
      {/* Header / toggle */}
      <div style={headerStyle} onClick={() => setOpen((o) => !o)} role="button">
        <SectionLabel>POI Веса</SectionLabel>
        <span
          style={{
            fontSize: 10,
            color: "#9ca3af",
            transform: open ? "rotate(180deg)" : "none",
            display: "inline-block",
            transition: "transform 0.15s",
          }}
        >
          ▼
        </span>
      </div>

      {open && (
        <div style={bodyStyle}>
          {/* Profile selector */}
          {canUseCrud && (
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <label
                style={{ fontSize: 12, color: "#6b7280", whiteSpace: "nowrap" }}
              >
                Профиль:
              </label>
              <select
                style={{
                  flex: 1,
                  padding: "4px 8px",
                  fontSize: 12,
                  border: "1px solid #d1d5db",
                  borderRadius: 6,
                }}
                value={selectedProfileId ?? ""}
                onChange={(e) => {
                  const val = e.target.value;
                  if (val === "") {
                    handleReset();
                  } else {
                    const p = profiles.find((x) => x.id === parseInt(val, 10));
                    if (p) handleLoadProfile(p);
                  }
                }}
              >
                <option value="">По умолчанию</option>
                {profiles.map((p) => (
                  <option key={p.id} value={p.id}>
                    {p.profile_name}
                    {p.is_default ? " ★" : ""}
                  </option>
                ))}
              </select>
              {profilesQuery.isLoading && (
                <span style={{ fontSize: 11, color: "#9ca3af" }}>…</span>
              )}
            </div>
          )}

          {/* Hint when no crud */}
          {!canUseCrud && (
            <p style={{ fontSize: 11, color: "#9ca3af", margin: 0 }}>
              Укажите User ID и Admin Token для сохранения профилей.
            </p>
          )}

          {/* Sliders */}
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {POI_CATEGORIES.map((cat) => {
              const value = draft[cat];
              return (
                <div key={cat} style={sliderRowStyle}>
                  <span style={{ fontSize: 12, color: "#374151" }}>
                    {POI_LABELS[cat]}
                  </span>
                  <input
                    type="range"
                    min={POI_WEIGHT_MIN}
                    max={POI_WEIGHT_MAX}
                    step={0.1}
                    value={value}
                    style={{ width: "100%", accentColor: "#1d4ed8" }}
                    onChange={(e) => handleSliderChange(cat, e.target.value)}
                  />
                  <span style={valueChipStyle(value)}>{value.toFixed(1)}</span>
                </div>
              );
            })}
          </div>

          {/* Action buttons */}
          <div
            style={{ display: "flex", gap: 8, flexWrap: "wrap", paddingTop: 4 }}
          >
            <button style={btnStyle("secondary")} onClick={handleReset}>
              Сбросить
            </button>

            {canUseCrud && isDraftDifferentFromDefaults && (
              <button
                style={btnStyle("secondary")}
                onClick={() => setShowSaveDialog(true)}
              >
                Сохранить как профиль
              </button>
            )}

            <button
              style={{
                ...btnStyle("primary"),
                opacity: isDirty ? 1 : 0.5,
                cursor: isDirty ? "pointer" : "default",
                marginLeft: "auto",
              }}
              onClick={handleApply}
              disabled={!isDirty}
            >
              Применить
            </button>
          </div>

          {/* Info: weights changed but not applied */}
          {isDirty && (
            <p style={{ fontSize: 11, color: "#f59e0b", margin: 0 }}>
              Изменения не применены к анализу — нажмите «Применить» перед
              запуском.
            </p>
          )}

          {/* Save dialog */}
          {showSaveDialog && (
            <div
              style={{
                background: "#f9fafb",
                border: "1px solid #e5e7eb",
                borderRadius: 8,
                padding: "12px 14px",
                display: "flex",
                flexDirection: "column",
                gap: 8,
              }}
            >
              <SectionLabel>Новый профиль</SectionLabel>
              <input
                autoFocus
                type="text"
                placeholder="Название профиля"
                value={saveName}
                onChange={(e) => setSaveName(e.target.value)}
                style={{
                  padding: "6px 10px",
                  fontSize: 13,
                  border: "1px solid #d1d5db",
                  borderRadius: 6,
                }}
                onKeyDown={(e) => {
                  if (e.key === "Enter") void handleSaveProfile();
                  if (e.key === "Escape") setShowSaveDialog(false);
                }}
              />
              <label
                style={{
                  display: "flex",
                  alignItems: "center",
                  gap: 6,
                  fontSize: 12,
                }}
              >
                <input
                  type="checkbox"
                  checked={saveDefault}
                  onChange={(e) => setSaveDefault(e.target.checked)}
                />
                Установить по умолчанию
              </label>
              <div style={{ display: "flex", gap: 8 }}>
                <button
                  style={btnStyle("primary")}
                  disabled={!saveName.trim() || createMutation.isPending}
                  onClick={() => void handleSaveProfile()}
                >
                  {createMutation.isPending ? "Сохранение…" : "Сохранить"}
                </button>
                <button
                  style={btnStyle("secondary")}
                  onClick={() => setShowSaveDialog(false)}
                >
                  Отмена
                </button>
              </div>
              {createMutation.error && (
                <p style={{ fontSize: 11, color: "#dc2626", margin: 0 }}>
                  {createMutation.error.message}
                </p>
              )}
            </div>
          )}
        </div>
      )}
    </div>
  );
}
