"use client";

import React, { useCallback, useMemo, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { useBuilderDispatch, useBuilderState } from "@/lib/admin/builder/context";
import { AddScreenDialog } from "../dialogs/AddScreenDialog";
import type {
  ListOptionDefinition,
  NavigationConditionDefinition,
  ScreenDefinition,
} from "@/lib/funnel/types";
import { cn } from "@/lib/utils";
import { DropIndicator } from "./DropIndicator";
import { InsertScreenButton } from "./InsertScreenButton";
import { TransitionRow } from "./TransitionRow";
import { TemplateSummary } from "./TemplateSummary";
import { VariantSummary } from "./VariantSummary";
import { getOptionLabel } from "./utils";
import { TEMPLATE_TITLES, OPERATOR_LABELS } from "./constants";

export function BuilderCanvas() {
  const { screens, selectedScreenId } = useBuilderState();
  const dispatch = useBuilderDispatch();

  const dragStateRef = useRef<{ screenId: string; dragStartIndex: number } | null>(null);
  const [dropIndex, setDropIndex] = useState<number | null>(null);
  const [addScreenDialogOpen, setAddScreenDialogOpen] = useState(false);
  const [insertScreenDialogOpen, setInsertScreenDialogOpen] = useState(false);
  const [insertAtIndex, setInsertAtIndex] = useState<number | null>(null);

  const handleDragStart = useCallback((event: React.DragEvent, screenId: string, index: number) => {
    event.dataTransfer.effectAllowed = "move";
    event.dataTransfer.setData("text/plain", screenId);
    dragStateRef.current = { screenId, dragStartIndex: index };
    setDropIndex(index);
  }, []);

  const handleDragOverCard = useCallback((event: React.DragEvent<HTMLDivElement>, index: number) => {
    event.preventDefault();
    if (!dragStateRef.current) {
      return;
    }

    const rect = event.currentTarget.getBoundingClientRect();
    const offsetY = event.clientY - rect.top;
    const nextIndex = offsetY > rect.height / 2 ? index + 1 : index;
    setDropIndex(nextIndex);
  }, []);

  const handleDragOverList = useCallback(
    (event: React.DragEvent<HTMLDivElement>) => {
      if (!dragStateRef.current) {
        return;
      }
      event.preventDefault();
      if (event.target === event.currentTarget) {
        setDropIndex(screens.length);
      }
    },
    [screens.length]
  );

  const finalizeDrop = useCallback(
    (insertionIndex: number | null) => {
      if (!dragStateRef.current) {
        return;
      }

      const { dragStartIndex } = dragStateRef.current;
      const boundedIndex = Math.max(0, Math.min(insertionIndex ?? dragStartIndex, screens.length));
      let targetIndex = boundedIndex;

      if (targetIndex > dragStartIndex) {
        targetIndex -= 1;
      }

      if (dragStartIndex !== targetIndex) {
        dispatch({
          type: "reorder-screens",
          payload: {
            fromIndex: dragStartIndex,
            toIndex: targetIndex,
          },
        });
      }

      dragStateRef.current = null;
      setDropIndex(null);
    },
    [dispatch, screens.length]
  );

  const handleDrop = useCallback(
    (event: React.DragEvent<HTMLDivElement>) => {
      event.preventDefault();
      finalizeDrop(dropIndex);
    },
    [dropIndex, finalizeDrop]
  );

  const handleDragEnd = useCallback(() => {
    dragStateRef.current = null;
    setDropIndex(null);
  }, []);

  const handleSelectScreen = useCallback(
    (screenId: string) => {
      dispatch({ type: "set-selected-screen", payload: { screenId } });
    },
    [dispatch]
  );

  const handleAddScreen = useCallback(() => {
    setAddScreenDialogOpen(true);
  }, []);

  const handleAddScreenWithTemplate = useCallback((template: ScreenDefinition["template"]) => {
    dispatch({ type: "add-screen", payload: { template } });
  }, [dispatch]);

  const handleInsertScreen = useCallback((atIndex: number) => {
    setInsertAtIndex(atIndex);
    setInsertScreenDialogOpen(true);
  }, []);

  const handleInsertScreenWithTemplate = useCallback((template: ScreenDefinition["template"]) => {
    if (insertAtIndex !== null) {
      dispatch({ type: "insert-screen", payload: { template, atIndex: insertAtIndex } });
    }
  }, [dispatch, insertAtIndex]);

  const screenTitleMap = useMemo(() => {
    return screens.reduce<Record<string, string>>((accumulator, screen) => {
      accumulator[screen.id] = screen.title?.text || screen.id;
      return accumulator;
    }, {});
  }, [screens]);

  const listOptionsMap = useMemo(() => {
    return screens.reduce<Record<string, ListOptionDefinition[]>>((accumulator, screen) => {
      if (screen.template === "list") {
        accumulator[screen.id] = screen.list.options;
      }
      return accumulator;
    }, {});
  }, [screens]);

  return (
    <>
    <div className="flex h-full flex-col">
      <div className="sticky top-0 z-30 flex items-center justify-between border-b border-border/60 bg-background/95 px-6 py-4 backdrop-blur-sm">
        <div>
          <h2 className="text-lg font-semibold">Экраны воронки</h2>
        </div>
        <Button variant="outline" className="w-8 h-8 p-0 flex items-center justify-center" onClick={handleAddScreen}>
          <span className="text-lg leading-none">+</span>
        </Button>
      </div>

      <div className="relative flex-1 overflow-auto bg-slate-50 p-6 dark:bg-slate-900">
        <div className="relative mx-auto w-full max-w-none">
          <div
            className="space-y-6"
            onDragOver={handleDragOverList}
            onDrop={handleDrop}
          >
            {screens.map((screen, index) => {
              const isSelected = screen.id === selectedScreenId;
              const isDropBefore = dropIndex === index;
              const isDropAfter = dropIndex === screens.length && index === screens.length - 1;
              const rules = screen.navigation?.rules ?? [];
              const defaultNext = screen.navigation?.defaultNextScreenId;
              const defaultTargetIndex = defaultNext
                ? screens.findIndex((candidate) => candidate.id === defaultNext)
                : null;
              const onBackScreenId = screen.navigation?.onBackScreenId;
              const backTargetIndex = onBackScreenId
                ? screens.findIndex((candidate) => candidate.id === onBackScreenId)
                : null;

              return (
                <div key={screen.id} className="relative">
                  {isDropBefore && <DropIndicator isActive={isDropBefore} />}
                  
                  <div>
                    <div
                      className={cn(
                        "relative flex-1 cursor-grab rounded-2xl border border-border/70 bg-background/95 p-5 shadow-sm transition-all hover:border-primary/40 hover:shadow-md",
                        isSelected && "border-primary/50 ring-2 ring-primary",
                        dragStateRef.current?.screenId === screen.id && "cursor-grabbing opacity-90"
                      )}
                      draggable
                      onDragStart={(event) => handleDragStart(event, screen.id, index)}
                      onDragOver={(event) => handleDragOverCard(event, index)}
                      onDragEnd={handleDragEnd}
                      onClick={() => handleSelectScreen(screen.id)}
                    >
                      <span className="absolute right-5 top-5 inline-flex items-center rounded-full bg-muted px-3 py-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                        {TEMPLATE_TITLES[screen.template] ?? screen.template}
                      </span>
                      <div className="pr-28">
                        <div className="flex items-start gap-3">
                          <div className="flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-sm font-semibold text-primary">
                            {index + 1}
                          </div>
                          <div className="flex flex-col gap-1">
                            <span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                              #{screen.id}
                            </span>
                            <span className="max-h-14 overflow-hidden break-words text-lg font-semibold leading-tight text-foreground">
                              {screen.title?.text || "Без названия"}
                            </span>
                          </div>
                        </div>
                      </div>

                      {("subtitle" in screen && screen.subtitle?.text) && (
                        <p className="mt-3 max-h-12 overflow-hidden text-sm leading-snug text-muted-foreground">
                          {screen.subtitle.text}
                        </p>
                      )}

                      <div className="mt-4 space-y-5">
                        <TemplateSummary screen={screen} />

                        <VariantSummary
                          screen={screen}
                          screenTitleMap={screenTitleMap}
                          listOptionsMap={listOptionsMap}
                        />

                        <div className="space-y-3">
                          <div className="flex items-center gap-2">
                            <span className="text-xs font-semibold uppercase text-muted-foreground">Переходы</span>
                            <div className="h-px flex-1 bg-border/60" />
                          </div>

                          <div className="space-y-3">
                            {onBackScreenId && (
                              <TransitionRow
                                type="back"
                                label="← Переход назад"
                                targetLabel={screenTitleMap[onBackScreenId] ?? onBackScreenId}
                                targetIndex={backTargetIndex !== -1 ? backTargetIndex : null}
                              />
                            )}

                            <TransitionRow
                              type={
                                screen.navigation?.isEndScreen 
                                  ? "end" 
                                  : defaultNext 
                                    ? "default" 
                                    : "end"
                              }
                              label={
                                screen.navigation?.isEndScreen 
                                  ? "🏁 Финальный экран" 
                                  : defaultNext 
                                    ? "По умолчанию" 
                                    : "Завершение"
                              }
                              targetLabel={defaultNext ? screenTitleMap[defaultNext] ?? defaultNext : undefined}
                              targetIndex={defaultNext && defaultTargetIndex !== -1 ? defaultTargetIndex : null}
                            />

                            {rules.map((rule, ruleIndex) => {
                              const condition = rule.conditions[0];
                              const optionSummaries =
                                screen.template === "list" && condition?.optionIds
                                  ? condition.optionIds.map((optionId) => ({
                                      id: optionId,
                                      label: getOptionLabel(screen.list.options, optionId),
                                    }))
                                  : [];

                              const operatorKey = condition?.operator as
                                | Exclude<NavigationConditionDefinition["operator"], undefined>
                                | undefined;
                              const operatorLabel = operatorKey
                                ? OPERATOR_LABELS[operatorKey] ?? operatorKey
                                : undefined;

                              const ruleTargetIndex = screens.findIndex(
                                (candidate) => candidate.id === rule.nextScreenId
                              );
                              const ruleTargetLabel = screenTitleMap[rule.nextScreenId] ?? rule.nextScreenId;

                              return (
                                <TransitionRow
                                  key={`${ruleIndex}-${rule.nextScreenId}`}
                                  type="branch"
                                  label="Вариативность"
                                  targetLabel={ruleTargetLabel}
                                  targetIndex={ruleTargetIndex !== -1 ? ruleTargetIndex : null}
                                  optionSummaries={optionSummaries}
                                  operator={operatorLabel}
                                />
                              );
                            })}
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  
                  {/* Insert button after each screen */}
                  <InsertScreenButton onInsert={() => handleInsertScreen(index + 1)} />
                  
                  {isDropAfter && <DropIndicator isActive={isDropAfter} />}
                </div>
              );
            })}

            {screens.length === 0 && (
              <div className="rounded-2xl border border-dashed border-border/60 bg-background/80 p-8 text-center text-sm text-muted-foreground">
                Добавьте первый экран, чтобы начать строить воронку.
              </div>
            )}

            <div className="pt-4">
              <Button variant="ghost" onClick={handleAddScreen} className="w-8 h-8 p-0 mx-auto flex items-center justify-center">
                +
              </Button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <AddScreenDialog 
      open={addScreenDialogOpen}
      onOpenChange={setAddScreenDialogOpen}
      onAddScreen={handleAddScreenWithTemplate}
    />
    
    <AddScreenDialog 
      open={insertScreenDialogOpen}
      onOpenChange={setInsertScreenDialogOpen}
      onAddScreen={handleInsertScreenWithTemplate}
    />
    </>
  );
}
