"use client";

import { useEffect, useMemo, useState, type ReactNode } from "react";
import { ChevronDown, ChevronRight } from "lucide-react";

import { TextInput } from "@/components/ui/TextInput/TextInput";
import { Button } from "@/components/ui/button";
import { TemplateConfig } from "@/components/admin/builder/templates";
import { ScreenVariantsConfig } from "@/components/admin/builder/ScreenVariantsConfig";
import { useBuilderDispatch, useBuilderSelectedScreen, useBuilderState } from "@/lib/admin/builder/context";
import type { BuilderScreen } from "@/lib/admin/builder/types";
import type {
  NavigationRuleDefinition,
  ScreenDefinition,
  ScreenVariantDefinition,
} from "@/lib/funnel/types";
import { cn } from "@/lib/utils";
import { validateBuilderState } from "@/lib/admin/builder/validation";

type ValidationIssues = ReturnType<typeof validateBuilderState>["issues"];

function isListScreen(
  screen: BuilderScreen
): screen is BuilderScreen & {
  list: {
    selectionType: "single" | "multi";
    options: Array<{ id: string; label: string; description?: string; emoji?: string }>;
  };
} {
  return screen.template === "list" && "list" in screen;
}

function Section({
  title,
  description,
  children,
  defaultExpanded = false,
  alwaysExpanded = false,
}: {
  title: string;
  description?: string;
  children: ReactNode;
  defaultExpanded?: boolean;
  alwaysExpanded?: boolean;
}) {
  const storageKey = `section-${title.toLowerCase().replace(/\s+/g, '-')}`;
  
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
  const [isHydrated, setIsHydrated] = useState(false);

  useEffect(() => {
    if (alwaysExpanded) {
      setIsExpanded(true);
      setIsHydrated(true);
      return;
    }
    
    const stored = sessionStorage.getItem(storageKey);
    if (stored !== null) {
      setIsExpanded(JSON.parse(stored));
    }
    setIsHydrated(true);
  }, [alwaysExpanded, storageKey]);

  const handleToggle = () => {
    if (alwaysExpanded) return;
    
    const newExpanded = !isExpanded;
    setIsExpanded(newExpanded);
    
    if (typeof window !== 'undefined') {
      sessionStorage.setItem(storageKey, JSON.stringify(newExpanded));
    }
  };

  const effectiveExpanded = alwaysExpanded || (isHydrated ? isExpanded : defaultExpanded);

  return (
    <section className="flex flex-col gap-3">
      <div 
        className={cn(
          "flex items-center gap-2 cursor-pointer",
          !alwaysExpanded && "hover:text-foreground transition-colors"
        )}
        onClick={handleToggle}
      >
        {!alwaysExpanded && (
          effectiveExpanded ? (
            <ChevronDown className="h-4 w-4 text-muted-foreground" />
          ) : (
            <ChevronRight className="h-4 w-4 text-muted-foreground" />
          )
        )}
        <div className="flex flex-col gap-1 flex-1">
          <h2 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">{title}</h2>
          {description && <p className="text-xs text-muted-foreground/80">{description}</p>}
        </div>
      </div>
      {effectiveExpanded && (
        <div className="flex flex-col gap-2 ml-2 pl-2 border-l-2 border-border/30">{children}</div>
      )}
    </section>
  );
}

function ValidationSummary({ issues }: { issues: ValidationIssues }) {
  if (issues.length === 0) {
    return (
      <div className="rounded-lg border border-border/30 bg-background/40 p-2 text-xs text-muted-foreground">
        Всё хорошо — воронка валидна.
      </div>
    );
  }

  return (
    <div className="space-y-2">
      {issues.map((issue, index) => (
        <div
          key={index}
          className="rounded-lg border border-destructive/20 bg-destructive/5 p-2 text-xs text-destructive"
        >
          <div className="flex items-start gap-2">
            <span className="text-destructive/80">⚠</span>
            <div>
              <p className="font-medium">{issue.message}</p>
              {issue.screenId && <p className="mt-1 text-destructive/80">Экран: {issue.screenId}</p>}
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

export function BuilderSidebar() {
  const state = useBuilderState();
  const dispatch = useBuilderDispatch();
  const selectedScreen = useBuilderSelectedScreen();

  const [activeTab, setActiveTab] = useState<"funnel" | "screen">(selectedScreen ? "screen" : "funnel");
  const selectedScreenId = selectedScreen?.id ?? null;

  useEffect(() => {
    setActiveTab((previous) => {
      if (selectedScreenId) {
        return "screen";
      }
      return previous === "screen" ? "funnel" : previous;
    });
  }, [selectedScreenId]);

  const validation = useMemo(() => validateBuilderState(state), [state]);
  const screenValidationIssues = useMemo(() => {
    if (!selectedScreenId) {
      return [] as ValidationIssues;
    }

    return validation.issues.filter((issue) => issue.screenId === selectedScreenId);
  }, [selectedScreenId, validation]);

  const screenOptions = useMemo(
    () => state.screens.map((screen) => ({ id: screen.id, title: screen.title.text })),
    [state.screens]
  );

  const handleMetaChange = (field: keyof typeof state.meta, value: string) => {
    dispatch({ type: "set-meta", payload: { [field]: value } });
  };

  const handleFirstScreenChange = (value: string) => {
    dispatch({ type: "set-meta", payload: { firstScreenId: value } });
  };

  const handleScreenIdChange = (currentId: string, newId: string) => {
    if (newId.trim() === "" || newId === currentId) {
      return;
    }
    
    // Обновляем ID экрана
    dispatch({ 
      type: "update-screen", 
      payload: { 
        screenId: currentId, 
        screen: { id: newId } 
      } 
    });
    
    // Если это был первый экран в мета данных, обновляем и там
    if (state.meta.firstScreenId === currentId) {
      dispatch({ type: "set-meta", payload: { firstScreenId: newId } });
    }
  };

  const getScreenById = (screenId: string): BuilderScreen | undefined =>
    state.screens.find((item) => item.id === screenId);

  const updateNavigation = (
    screen: BuilderScreen,
    navigationUpdates: Partial<BuilderScreen["navigation"]> = {}
  ) => {
    dispatch({
      type: "update-navigation",
      payload: {
        screenId: screen.id,
        navigation: {
          defaultNextScreenId:
            navigationUpdates.defaultNextScreenId ?? screen.navigation?.defaultNextScreenId,
          rules: navigationUpdates.rules ?? screen.navigation?.rules ?? [],
        },
      },
    });
  };

  const handleDefaultNextChange = (screenId: string, nextScreenId: string | "") => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    updateNavigation(screen, {
      defaultNextScreenId: nextScreenId || undefined,
    });
  };

  const updateRules = (screenId: string, rules: NavigationRuleDefinition[]) => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    updateNavigation(screen, { rules });
  };

  const handleRuleOperatorChange = (
    screenId: string,
    index: number,
    operator: NavigationRuleDefinition["conditions"][0]["operator"]
  ) => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    const rules = screen.navigation?.rules ?? [];
    const nextRules = rules.map((rule, ruleIndex) =>
      ruleIndex === index
        ? {
            ...rule,
            conditions: rule.conditions.map((condition, conditionIndex) =>
              conditionIndex === 0
                ? {
                    ...condition,
                    operator,
                  }
                : condition
            ),
          }
        : rule
    );

    updateRules(screenId, nextRules);
  };

  const handleRuleOptionToggle = (screenId: string, ruleIndex: number, optionId: string) => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    const rules = screen.navigation?.rules ?? [];
    const nextRules = rules.map((rule, currentIndex) => {
      if (currentIndex !== ruleIndex) {
        return rule;
      }

      const [condition] = rule.conditions;
      const optionIds = new Set(condition.optionIds ?? []);
      if (optionIds.has(optionId)) {
        optionIds.delete(optionId);
      } else {
        optionIds.add(optionId);
      }

      return {
        ...rule,
        conditions: [
          {
            ...condition,
            optionIds: Array.from(optionIds),
          },
        ],
      };
    });

    updateRules(screenId, nextRules);
  };

  const handleRuleNextScreenChange = (screenId: string, ruleIndex: number, nextScreenId: string) => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    const rules = screen.navigation?.rules ?? [];
    const nextRules = rules.map((rule, currentIndex) =>
      currentIndex === ruleIndex ? { ...rule, nextScreenId } : rule
    );

    updateRules(screenId, nextRules);
  };

  const handleAddRule = (screen: BuilderScreen) => {
    if (!isListScreen(screen)) {
      return;
    }

    const defaultCondition: NavigationRuleDefinition["conditions"][number] = {
      screenId: screen.id,
      operator: "includesAny",
      optionIds: screen.list.options.slice(0, 1).map((option) => option.id),
    };

    const nextRules = [
      ...(screen.navigation?.rules ?? []),
      { nextScreenId: state.screens[0]?.id ?? screen.id, conditions: [defaultCondition] },
    ];
    updateNavigation(screen, { rules: nextRules });
  };

  const handleRemoveRule = (screenId: string, ruleIndex: number) => {
    const screen = getScreenById(screenId);
    if (!screen) {
      return;
    }

    const rules = screen.navigation?.rules ?? [];
    const nextRules = rules.filter((_, index) => index !== ruleIndex);
    updateNavigation(screen, { rules: nextRules });
  };

  const handleDeleteScreen = (screenId: string) => {
    if (state.screens.length <= 1) {
      return;
    }
    dispatch({ type: "remove-screen", payload: { screenId } });
  };

  const handleTemplateUpdate = (screenId: string, updates: Partial<ScreenDefinition>) => {
    dispatch({
      type: "update-screen",
      payload: {
        screenId,
        screen: updates as Partial<BuilderScreen>,
      },
    });
  };

  const handleVariantsChange = (
    screenId: string,
    variants: ScreenVariantDefinition<ScreenDefinition>[]
  ) => {
    dispatch({
      type: "update-screen",
      payload: {
        screenId,
        screen: {
          variants: variants.length > 0 ? variants : undefined,
        } as Partial<BuilderScreen>,
      },
    });
  };

  const selectedScreenIsListType = selectedScreen ? isListScreen(selectedScreen) : false;

  return (
    <div className="flex h-full flex-col">
      <div className="sticky top-0 z-20 border-b border-border/60 bg-background/95 px-4 py-3">
        <div className="flex flex-col gap-1">
          <h1 className="text-base font-semibold">Настройки</h1>
        </div>
        <div className="mt-3 flex rounded-lg bg-muted/40 p-1 text-sm font-medium">
          <button
            type="button"
            className={cn(
              "flex-1 rounded-md px-3 py-1.5 transition",
              activeTab === "funnel"
                ? "bg-background text-foreground shadow"
                : "text-muted-foreground hover:text-foreground"
            )}
            onClick={() => setActiveTab("funnel")}
          >
            Воронка
          </button>
          <button
            type="button"
            className={cn(
              "flex-1 rounded-md px-3 py-1.5 transition",
              activeTab === "screen"
                ? "bg-background text-foreground shadow"
                : "text-muted-foreground hover:text-foreground",
              !selectedScreen && "cursor-not-allowed opacity-60"
            )}
            onClick={() => selectedScreen && setActiveTab("screen")}
          >
            Экран
          </button>
        </div>
      </div>

      <div className="flex-1 overflow-y-auto px-4 py-4">
        {activeTab === "funnel" ? (
          <div className="flex flex-col gap-4">
            <Section title="Валидация">
              <ValidationSummary issues={validation.issues} />
            </Section>

            <Section title="Настройки воронки" description="Общие параметры">
              <TextInput
                label="ID воронки"
                value={state.meta.id}
                onChange={(event) => handleMetaChange("id", event.target.value)}
              />
              <TextInput
                label="Название"
                value={state.meta.title ?? ""}
                onChange={(event) => handleMetaChange("title", event.target.value)}
              />
              <TextInput
                label="Описание"
                value={state.meta.description ?? ""}
                onChange={(event) => handleMetaChange("description", event.target.value)}
              />
              <label className="flex flex-col gap-2">
                <span className="text-sm font-medium text-muted-foreground">Первый экран</span>
                <select
                  className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                  value={state.meta.firstScreenId ?? state.screens[0]?.id ?? ""}
                  onChange={(event) => handleFirstScreenChange(event.target.value)}
                >
                  {screenOptions.map((screen) => (
                    <option key={screen.id} value={screen.id}>
                      {screen.title}
                    </option>
                  ))}
                </select>
              </label>
            </Section>

            <Section title="Экраны">
              <div className="flex flex-col gap-3 rounded-lg border border-border/60 bg-muted/20 p-3 text-sm text-muted-foreground">
                <div className="flex items-center justify-between">
                  <span>Всего экранов</span>
                  <span className="font-semibold text-foreground">{state.screens.length}</span>
                </div>
                <div className="flex flex-col gap-1 text-xs">
                  {state.screens.map((screen, index) => (
                    <span key={screen.id} className="flex items-center justify-between">
                      <span className="truncate">{index + 1}. {screen.title.text}</span>
                      <span className="uppercase text-muted-foreground/80">{screen.template}</span>
                    </span>
                  ))}
                </div>
              </div>
            </Section>
          </div>
        ) : selectedScreen ? (
          <div className="flex flex-col gap-4">
            <div className="rounded-lg border border-primary/20 bg-primary/5 p-3">
              <div className="flex items-center justify-between text-sm">
                <div className="flex items-center gap-2">
                  <span className="text-muted-foreground">#{selectedScreen.id}</span>
                  <span className="inline-flex items-center rounded-full bg-primary/10 px-2 py-0.5 text-xs font-medium text-primary uppercase">
                    {selectedScreen.template}
                  </span>
                </div>
                <span className="text-xs text-muted-foreground">
                  {state.screens.findIndex((screen) => screen.id === selectedScreen.id) + 1}/{state.screens.length}
                </span>
              </div>
            </div>

            <Section title="Общие данные">
              <TextInput 
                label="ID экрана" 
                value={selectedScreen.id} 
                onChange={(event) => handleScreenIdChange(selectedScreen.id, event.target.value)}
              />
            </Section>

            <Section title="Контент и оформление">
              <TemplateConfig
                screen={selectedScreen}
                onUpdate={(updates) => handleTemplateUpdate(selectedScreen.id, updates)}
              />
            </Section>

            <Section title="Вариативность">
              <ScreenVariantsConfig
                screen={selectedScreen}
                allScreens={state.screens}
                onChange={(variants) => handleVariantsChange(selectedScreen.id, variants)}
              />
            </Section>

            <Section title="Навигация">
              <label className="flex flex-col gap-2">
                <span className="text-sm font-medium text-muted-foreground">Экран по умолчанию</span>
                <select
                  className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                  value={selectedScreen.navigation?.defaultNextScreenId ?? ""}
                  onChange={(event) => handleDefaultNextChange(selectedScreen.id, event.target.value)}
                >
                  <option value="">—</option>
                  {screenOptions
                    .filter((screen) => screen.id !== selectedScreen.id)
                    .map((screen) => (
                      <option key={screen.id} value={screen.id}>
                        {screen.title}
                      </option>
                    ))}
                </select>
              </label>
            </Section>

            {selectedScreenIsListType && (
              <Section title="Правила переходов" description="Условная навигация">
                <div className="flex flex-col gap-3">
                  <div className="flex items-center justify-between">
                    <p className="text-xs text-muted-foreground">
                      Направляйте пользователей на разные экраны в зависимости от выбора.
                    </p>
                    <Button className="h-8 w-8 p-0 flex items-center justify-center" onClick={() => handleAddRule(selectedScreen)}>
                      <span className="text-lg leading-none">+</span>
                    </Button>
                  </div>

                  {(selectedScreen.navigation?.rules ?? []).length === 0 && (
                    <div className="rounded-lg border border-border/60 bg-muted/30 p-3 text-center text-xs text-muted-foreground">
                      Правил пока нет
                    </div>
                  )}

                  {(selectedScreen.navigation?.rules ?? []).map((rule, ruleIndex) => (
                    <div
                      key={ruleIndex}
                      className="flex flex-col gap-3 rounded-xl border border-border/80 bg-background/60 p-3"
                    >
                      <div className="flex items-center justify-between">
                        <span className="text-xs font-semibold uppercase text-muted-foreground">Правило {ruleIndex + 1}</span>
                        <Button
                          variant="ghost"
                          className="text-destructive"
                          onClick={() => handleRemoveRule(selectedScreen.id, ruleIndex)}
                        >
                          <span className="text-xs">Удалить</span>
                        </Button>
                      </div>
                      <label className="flex flex-col gap-2">
                        <span className="text-sm font-medium text-muted-foreground">Оператор</span>
                        <select
                          className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                          value={rule.conditions[0]?.operator ?? "includesAny"}
                          onChange={(event) =>
                            handleRuleOperatorChange(
                              selectedScreen.id,
                              ruleIndex,
                              event.target.value as NavigationRuleDefinition["conditions"][0]["operator"]
                            )
                          }
                        >
                          <option value="includesAny">contains any</option>
                          <option value="includesAll">contains all</option>
                          <option value="includesExactly">exact match</option>
                        </select>
                      </label>

                      {selectedScreen.template === "list" ? (
                        <div className="flex flex-col gap-2">
                          <span className="text-sm font-medium text-muted-foreground">Варианты ответа</span>
                          <div className="flex flex-col gap-2 rounded-lg border border-border/60 p-3">
                            {selectedScreen.list.options.map((option) => {
                              const condition = rule.conditions[0];
                              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={() => handleRuleOptionToggle(selectedScreen.id, ruleIndex, option.id)}
                                  />
                                  <span>
                                    {option.label}
                                    <span className="text-muted-foreground"> ({option.id})</span>
                                  </span>
                                </label>
                              );
                            })}
                          </div>
                        </div>
                      ) : (
                        <div className="flex flex-col gap-2 rounded-lg border border-border/60 bg-muted/20 p-3 text-xs text-muted-foreground">
                          Навигационные правила с вариантами ответа доступны только для экранов со списком.
                        </div>
                      )}

                      <label className="flex flex-col gap-2">
                        <span className="text-sm font-medium text-muted-foreground">Следующий экран</span>
                        <select
                          className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
                          value={rule.nextScreenId}
                          onChange={(event) => handleRuleNextScreenChange(selectedScreen.id, ruleIndex, event.target.value)}
                        >
                          {screenOptions
                            .filter((screen) => screen.id !== selectedScreen.id)
                            .map((screen) => (
                              <option key={screen.id} value={screen.id}>
                                {screen.title}
                              </option>
                            ))}
                        </select>
                      </label>
                    </div>
                  ))}
                </div>
              </Section>
            )}

            <Section title="Валидация">
              <ValidationSummary issues={screenValidationIssues} />
            </Section>

            <Section title="Управление">
              <div className="rounded-lg border border-destructive/20 bg-destructive/5 p-4">
                <p className="mb-3 text-sm text-muted-foreground">
                  Удаление экрана нельзя отменить. Все связи с этим экраном будут потеряны.
                </p>
                <Button
                  variant="destructive"
                  className="h-9 text-sm"
                  disabled={state.screens.length <= 1}
                  onClick={() => handleDeleteScreen(selectedScreen.id)}
                >
                  {state.screens.length <= 1 ? "Нельзя удалить последний экран" : "Удалить экран"}
                </Button>
              </div>
            </Section>
          </div>
        ) : (
          <div className="flex h-full items-center justify-center rounded-xl border border-dashed border-border/60 bg-muted/20 p-6 text-center text-sm text-muted-foreground">
            Выберите экран в списке слева, чтобы настроить его параметры.
          </div>
        )}
      </div>
    </div>
  );
}
