"use client";

import { useCallback, useEffect, useMemo, useState } from "react";

import { TemplateConfig } from "@/components/admin/builder/templates";
import { Button } from "@/components/ui/button";
import type { BuilderScreen } from "@/lib/admin/builder/types";
import {
  extractVariantOverrides,
  formatOverridePath,
  listOverridePaths,
  mergeScreenWithOverrides,
} from "@/lib/admin/builder/variants";
import type {
  ListOptionDefinition,
  NavigationConditionDefinition,
  ScreenDefinition,
  ScreenVariantDefinition,
} from "@/lib/funnel/types";

interface ScreenVariantsConfigProps {
  screen: BuilderScreen;
  allScreens: BuilderScreen[];
  onChange: (variants: ScreenVariantDefinition<ScreenDefinition>[]) => void;
}

type ListBuilderScreen = BuilderScreen & { template: "list" };

type VariantDefinition = ScreenVariantDefinition<ScreenDefinition>;

type VariantCondition = NavigationConditionDefinition;

function ensureCondition(variant: VariantDefinition, fallbackScreenId: string): VariantCondition {
  const [condition] = variant.conditions;

  if (!condition) {
    return {
      screenId: fallbackScreenId,
      operator: "includesAny",
      optionIds: [],
    };
  }

  return condition;
}

function VariantOverridesEditor({
  baseScreen,
  overrides,
  onChange,
}: {
  baseScreen: BuilderScreen;
  overrides: VariantDefinition["overrides"];
  onChange: (overrides: VariantDefinition["overrides"]) => void;
}) {
  const baseWithoutVariants = useMemo(() => {
    const clone = mergeScreenWithOverrides(baseScreen, {});
    const sanitized = { ...clone } as BuilderScreen;
    if ("variants" in sanitized) {
      delete (sanitized as Partial<BuilderScreen>).variants;
    }
    return sanitized;
  }, [baseScreen]);

  const mergedScreen = useMemo(
    () => mergeScreenWithOverrides(baseWithoutVariants, overrides),
    [baseWithoutVariants, overrides]
  );

  const handleUpdate = useCallback(
    (updates: Partial<ScreenDefinition>) => {
      const nextScreen = mergeScreenWithOverrides(mergedScreen, updates as Partial<ScreenDefinition>);
      const nextOverrides = extractVariantOverrides(baseWithoutVariants, nextScreen);
      onChange(nextOverrides);
    },
    [baseWithoutVariants, mergedScreen, onChange]
  );

  return (
    <div className="space-y-3">
      <TemplateConfig screen={mergedScreen} onUpdate={handleUpdate} />
      <Button variant="outline" size="sm" onClick={() => onChange({})}>
        Сбросить переопределения
      </Button>
    </div>
  );
}

export function ScreenVariantsConfig({ screen, allScreens, onChange }: ScreenVariantsConfigProps) {
  const variants = useMemo(
    () => ((screen.variants ?? []) as VariantDefinition[]),
    [screen.variants]
  );
  const [expandedVariant, setExpandedVariant] = useState<number | null>(() => (variants.length > 0 ? 0 : null));

  useEffect(() => {
    if (variants.length === 0) {
      setExpandedVariant(null);
      return;
    }

    if (expandedVariant === null) {
      setExpandedVariant(0);
      return;
    }

    if (expandedVariant >= variants.length) {
      setExpandedVariant(variants.length - 1);
    }
  }, [expandedVariant, variants]);

  const listScreens = useMemo(
    () => allScreens.filter((candidate): candidate is ListBuilderScreen => candidate.template === "list"),
    [allScreens]
  );

  const optionMap = useMemo(() => {
    return listScreens.reduce<Record<string, ListOptionDefinition[]>>((accumulator, listScreen) => {
      accumulator[listScreen.id] = listScreen.list.options;
      return accumulator;
    }, {});
  }, [listScreens]);

  const handleVariantsUpdate = useCallback(
    (nextVariants: VariantDefinition[]) => {
      onChange(nextVariants);
    },
    [onChange]
  );

  const addVariant = useCallback(() => {
    const fallbackScreen = listScreens[0] ?? (screen.template === "list" ? (screen as ListBuilderScreen) : undefined);

    if (!fallbackScreen) {
      return;
    }

    const firstOptionId = fallbackScreen.list.options[0]?.id;

    const newVariant: VariantDefinition = {
      conditions: [
        {
          screenId: fallbackScreen.id,
          operator: "includesAny",
          optionIds: firstOptionId ? [firstOptionId] : [],
        },
      ],
      overrides: {},
    };

    handleVariantsUpdate([...variants, newVariant]);
    setExpandedVariant(variants.length);
  }, [handleVariantsUpdate, listScreens, screen, variants]);

  const removeVariant = useCallback(
    (index: number) => {
      handleVariantsUpdate(variants.filter((_, variantIndex) => variantIndex !== index));
    },
    [handleVariantsUpdate, variants]
  );

  const updateVariant = useCallback(
    (index: number, patch: Partial<VariantDefinition>) => {
      handleVariantsUpdate(
        variants.map((variant, variantIndex) =>
          variantIndex === index
            ? {
                ...variant,
                ...patch,
                conditions: patch.conditions ?? variant.conditions,
                overrides: patch.overrides ?? variant.overrides,
              }
            : variant
        )
      );
    },
    [handleVariantsUpdate, variants]
  );

  const updateCondition = useCallback(
    (index: number, updates: Partial<VariantCondition>) => {
      updateVariant(index, {
        conditions: [
          {
            ...ensureCondition(variants[index], screen.id),
            ...updates,
          },
        ],
      });
    },
    [screen.id, updateVariant, variants]
  );

  const toggleOption = useCallback(
    (index: number, optionId: string) => {
      const condition = ensureCondition(variants[index], screen.id);
      const optionIds = new Set(condition.optionIds ?? []);
      if (optionIds.has(optionId)) {
        optionIds.delete(optionId);
      } else {
        optionIds.add(optionId);
      }

      updateCondition(index, { optionIds: Array.from(optionIds) });
    },
    [screen.id, updateCondition, variants]
  );

  const handleScreenChange = useCallback(
    (variantIndex: number, screenId: string) => {
      const listScreen = listScreens.find((candidate) => candidate.id === screenId);
      const defaultOption = listScreen?.list.options[0]?.id;
      updateCondition(variantIndex, {
        screenId,
        optionIds: defaultOption ? [defaultOption] : [],
      });
    },
    [listScreens, updateCondition]
  );

  const handleOperatorChange = useCallback(
    (variantIndex: number, operator: VariantCondition["operator"]) => {
      updateCondition(variantIndex, { operator });
    },
    [updateCondition]
  );

  const handleOverridesChange = useCallback(
    (index: number, overrides: VariantDefinition["overrides"]) => {
      updateVariant(index, { overrides });
    },
    [updateVariant]
  );

  const renderVariantSummary = useCallback(
    (variant: VariantDefinition) => {
      const condition = ensureCondition(variant, screen.id);
      const optionSummaries = (condition.optionIds ?? []).map((optionId) => {
        const options = optionMap[condition.screenId] ?? [];
        const option = options.find((item) => item.id === optionId);
        return option?.label ?? optionId;
      });

      const listScreenTitle = listScreens.find((candidate) => candidate.id === condition.screenId)?.title.text;
      const operatorLabel = (() => {
        switch (condition.operator) {
          case "includesAll":
            return "все из";
          case "includesExactly":
            return "точное совпадение";
          default:
            return "любой из";
        }
      })();

      const overrideHighlights = listOverridePaths(variant.overrides ?? {});

      return (
        <div className="space-y-1 text-xs text-muted-foreground">
          <div className="flex flex-wrap items-center gap-2">
            <span className="font-semibold text-foreground">Экран условий:</span>
            <span className="rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground">
              {listScreenTitle ?? condition.screenId}
            </span>
            <span className="rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground/80">{operatorLabel}</span>
          </div>
          {optionSummaries.length > 0 ? (
            <div className="flex flex-wrap gap-1">
              {optionSummaries.map((label) => (
                <span key={label} className="rounded-full bg-primary/10 px-2 py-0.5 text-[11px] text-primary">
                  {label}
                </span>
              ))}
            </div>
          ) : (
            <div className="text-muted-foreground/80">Пока нет выбранных ответов</div>
          )}
          <div className="flex flex-wrap gap-1">
            {(overrideHighlights.length > 0 ? overrideHighlights : ["Без изменений"]).map((item) => (
              <span key={item} className="rounded-md bg-muted px-2 py-0.5 text-[11px]">
                {item === "Без изменений" ? item : formatOverridePath(item)}
              </span>
            ))}
          </div>
        </div>
      );
    },
    [listScreens, optionMap, screen.id]
  );

  return (
    <div className="flex flex-col gap-3">
      <div className="flex items-start justify-between gap-3">
        <p className="text-xs text-muted-foreground">
          Настройте альтернативные варианты контента без изменения переходов.
        </p>
        <Button size="sm" onClick={addVariant} disabled={listScreens.length === 0}>
          Добавить вариант
        </Button>
      </div>

      {listScreens.length === 0 ? (
        <div className="rounded-lg border border-border/60 bg-muted/30 p-3 text-xs text-muted-foreground">
          Добавьте экран со списком, чтобы настроить вариативность.
        </div>
      ) : variants.length === 0 ? (
        <div className="rounded-lg border border-dashed border-border/60 bg-muted/20 p-4 text-center text-xs text-muted-foreground">
          Пока нет дополнительных вариантов.
        </div>
      ) : (
        <div className="flex flex-col gap-4">
          {variants.map((variant, index) => {
            const condition = ensureCondition(variant, screen.id);
            const isExpanded = expandedVariant === index;
            const availableOptions = optionMap[condition.screenId] ?? [];

            return (
              <div key={index} className="space-y-3 rounded-xl border border-border/70 bg-background/80 p-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <div className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                      Вариант {index + 1}
                    </div>
                    <div className="mt-1 text-xs text-muted-foreground">{renderVariantSummary(variant)}</div>
                  </div>
                  <div className="flex items-center gap-2">
                    <Button
                      variant="outline"
                      size="sm"
                      onClick={() => setExpandedVariant(isExpanded ? null : index)}
                    >
                      {isExpanded ? "Свернуть" : "Редактировать"}
                    </Button>
                    <Button variant="ghost" size="sm" className="text-destructive" onClick={() => removeVariant(index)}>
                      Удалить
                    </Button>
                  </div>
                </div>

                {isExpanded && (
                  <div className="space-y-4 border-t border-border/60 pt-4">
                    <div className="grid gap-3 md:grid-cols-2">
                      <label className="flex flex-col gap-1 text-sm">
                        <span className="text-xs font-semibold uppercase text-muted-foreground">Экран условий</span>
                        <select
                          className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                          value={condition.screenId}
                          onChange={(event) => handleScreenChange(index, event.target.value)}
                        >
                          {listScreens.map((candidate) => (
                            <option key={candidate.id} value={candidate.id}>
                              {candidate.title.text}
                            </option>
                          ))}
                        </select>
                      </label>
                      <label className="flex flex-col gap-1 text-sm">
                        <span className="text-xs font-semibold uppercase text-muted-foreground">Оператор</span>
                        <select
                          className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                          value={condition.operator ?? "includesAny"}
                          onChange={(event) =>
                            handleOperatorChange(index, event.target.value as VariantCondition["operator"])
                          }
                        >
                          <option value="includesAny">любой из</option>
                          <option value="includesAll">все из</option>
                          <option value="includesExactly">точное совпадение</option>
                        </select>
                      </label>
                    </div>

                    <div className="space-y-2">
                      <span className="text-xs font-semibold uppercase text-muted-foreground">Ответы</span>
                      {availableOptions.length === 0 ? (
                        <div className="rounded-lg border border-dashed border-border/60 bg-muted/20 p-3 text-xs text-muted-foreground">
                          В выбранном экране пока нет вариантов ответа.
                        </div>
                      ) : (
                        <div className="grid gap-2 md:grid-cols-2">
                          {availableOptions.map((option) => {
                            const isChecked = condition.optionIds?.includes(option.id) ?? false;
                            return (
                              <label key={option.id} className="flex items-center gap-2 text-sm">
                                <input
                                  type="checkbox"
                                  checked={isChecked}
                                  onChange={() => toggleOption(index, option.id)}
                                />
                                <span>
                                  {option.label}
                                  <span className="text-muted-foreground"> ({option.id})</span>
                                </span>
                              </label>
                            );
                          })}
                        </div>
                      )}
                    </div>

                    <div className="space-y-3">
                      <span className="text-xs font-semibold uppercase text-muted-foreground">Настройка контента</span>
                      <VariantOverridesEditor
                        baseScreen={screen}
                        overrides={variant.overrides ?? {}}
                        onChange={(overrides) => handleOverridesChange(index, overrides)}
                      />
                    </div>
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}
