import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import type { ElectricalItem, WallOpening, Annotation } from '@house-plan-maker/shared';
import { useEditor } from '../context/EditorContext';
import { wallDirectionKey, getProjectionAxis } from '../utils/projectionMapping';
import { generateLocalId } from '../utils/geometry';
import { normalizeAngleDegrees } from '../utils/angle';
import { TextPromptModal } from '../../ui/TextPromptModal';
import { getDefaultElevation } from '../tools/ElectricalTool';
import { ELECTRICAL_SYMBOL_DEFS } from '../symbols/electrical';
import { WallProjectionView } from './WallProjectionView';
import styles from './projection-panel.module.css';

type LayoutMode = 'tabs' | 'grid';

interface ProjectionPanelProps {
  readonly fullView?: boolean;
  readonly onStageRef?: (wallId: string, stage: import('konva').default.Stage | null) => void;
}

export function ProjectionPanel({ fullView = false, onStageRef }: ProjectionPanelProps = {}) {
  const { t } = useTranslation();
  const { state, selectElement, updateElectrical, updateOpening, addElectrical, updateAnnotation, addAnnotation } = useEditor();
  const {
    walls,
    openings,
    electricalItems,
    furnitureItems,
    annotations,
    globalFurnitureOpacity,
    room,
    selectedIds,
    activeTool,
    selectedElectricalIndex,
    layerVisibility,
  } = state;

  const [isCollapsed, setIsCollapsed] = useState(false);
  const [layoutMode, setLayoutMode] = useState<LayoutMode>('tabs');
  const [activeWallIndex, setActiveWallIndex] = useState(0);
  const contentRef = useRef<HTMLDivElement>(null);
  const [contentSize, setContentSize] = useState({ width: 600, height: 240 });

  // ── Determine active electrical type for placement ──
  const selectedElectricalType = useMemo(() => {
    if (activeTool !== 'electrical' || selectedElectricalIndex == null) return null;
    const def = ELECTRICAL_SYMBOL_DEFS[selectedElectricalIndex];
    return def?.type ?? null;
  }, [activeTool, selectedElectricalIndex]);

  // ── Determine which wall is selected in 2D view ──
  const highlightedWallId = useMemo(() => {
    for (const wall of walls) {
      if (selectedIds.has(wall.id)) return wall.id;
    }
    for (const opening of openings) {
      if (selectedIds.has(opening.id)) return opening.wallId;
    }
    for (const elec of electricalItems) {
      if (selectedIds.has(elec.id) && elec.wallId) return elec.wallId;
    }
    return null;
  }, [walls, openings, electricalItems, selectedIds]);

  // ── Auto-switch tab when a wall-related item is selected ──
  useEffect(() => {
    if (highlightedWallId && layoutMode === 'tabs') {
      const idx = walls.findIndex((w) => w.id === highlightedWallId);
      if (idx >= 0) {
        setActiveWallIndex(idx);
      }
    }
  }, [highlightedWallId, walls, layoutMode]);

  // ── Resize observer ──
  useEffect(() => {
    const container = contentRef.current;
    if (!container) return;

    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        setContentSize({ width: Math.floor(width), height: Math.floor(height) });
      }
    });

    observer.observe(container);
    const rect = container.getBoundingClientRect();
    setContentSize({ width: Math.floor(rect.width), height: Math.floor(rect.height) });

    return () => observer.disconnect();
  }, [isCollapsed, fullView]);

  const handleToggleCollapse = useCallback(() => {
    if (fullView) return;
    setIsCollapsed((prev) => !prev);
  }, [fullView]);

  const handleToggleLayout = useCallback(() => {
    setLayoutMode((prev) => (prev === 'tabs' ? 'grid' : 'tabs'));
  }, []);

  const handleSelectElement = useCallback(
    (id: string) => {
      selectElement(id);
    },
    [selectElement],
  );

  // ── Drag callbacks ──
  const handleUpdateElectrical = useCallback(
    (item: ElectricalItem) => {
      updateElectrical(item);
    },
    [updateElectrical],
  );

  const handleUpdateOpening = useCallback(
    (opening: WallOpening) => {
      updateOpening(opening);
    },
    [updateOpening],
  );

  const handleUpdateAnnotation = useCallback(
    (annotation: Annotation) => {
      updateAnnotation(annotation);
    },
    [updateAnnotation],
  );

  // ── Annotation editing modal (shared by all wall views) ──
  const [editingAnnotationId, setEditingAnnotationId] = useState<string | null>(null);
  const editingAnnotation = useMemo(
    () => (editingAnnotationId ? state.annotations.find((a) => a.id === editingAnnotationId) ?? null : null),
    [editingAnnotationId, state.annotations],
  );
  const handleEditAnnotation = useCallback((id: string) => setEditingAnnotationId(id), []);

  // ── Placement callback ──
  const handlePlaceElectrical = useCallback(
    (wallId: string, alongWall: number, fromFloor: number) => {
      if (selectedElectricalIndex == null) return;
      const symbolDef = ELECTRICAL_SYMBOL_DEFS[selectedElectricalIndex];
      if (!symbolDef) return;

      const wall = walls.find((w) => w.id === wallId);
      if (!wall) return;

      // Convert projection coordinates (alongWall) back to room 2D coordinates
      // using the canonical projection axis (so south/west walls aren't mirrored).
      const axis = getProjectionAxis(wall);
      const { start, end, length: wallLen } = axis;
      if (wallLen === 0) return;

      const dx = (end.x - start.x) / wallLen;
      const dy = (end.y - start.y) / wallLen;
      const x = start.x + dx * alongWall;
      const y = start.y + dy * alongWall;

      // Use the clicked elevation, or fall back to default for the type
      const elevation = symbolDef.wallMounted
        ? fromFloor
        : getDefaultElevation(symbolDef.type, room.wallHeight);

      // Outlets no longer use a metadata variant (count is the source of
      // truth). Other electrical types still pass variant through metadata.
      const metadata: Record<string, unknown> | null =
        symbolDef.type !== 'OUTLET' && symbolDef.variant ? { variant: symbolDef.variant } : null;

      const newItem: ElectricalItem = {
        id: generateLocalId(),
        roomId: room.id,
        type: symbolDef.type,
        x,
        y,
        wallId: symbolDef.wallMounted ? wallId : null,
        elevationFromFloor: elevation,
        rotation: normalizeAngleDegrees((Math.atan2(dy, dx) * 180) / Math.PI),
        count: 1,
        positionAnchor: { horizontal: 'middle', vertical: 'middle' },
        label: null,
        metadata,
      };

      addElectrical(newItem);
      selectElement(newItem.id);
    },
    [selectedElectricalIndex, walls, room, addElectrical, selectElement],
  );

  // Place a free-form annotation anchored to a wall at projection-space
  // (alongWall, fromFloor). Stored with attachedToId = wall.id and the
  // anchor point in (x, y); WallProjectionView reads these directly.
  const handlePlaceAnnotation = useCallback(
    (wallId: string, alongWall: number, fromFloor: number) => {
      const newAnnotation: Annotation = {
        id: generateLocalId(),
        roomId: room.id,
        x: alongWall,
        y: fromFloor,
        text: 'Text',
        fontSize: 12,
        color: '#334155',
        attachedToId: wallId,
        projectionOffsetX: 0,
        projectionOffsetY: 0,
      };
      addAnnotation(newAnnotation);
      selectElement(newAnnotation.id);
    },
    [room.id, addAnnotation, selectElement],
  );

  if (walls.length === 0) {
    return null;
  }

  const clampedIndex = Math.min(activeWallIndex, walls.length - 1);

  const sharedProps = {
    walls,
    openings,
    electricalItems: layerVisibility.electrical ? electricalItems : [],
    furnitureItems: layerVisibility.furniture ? furnitureItems : [],
    annotations: layerVisibility.annotations ? annotations : [],
    globalFurnitureOpacity,
    wallHeight: room.wallHeight,
    plinthHeight: room.plinthHeight,
    stretchCeilingOffset: layerVisibility.stretchCeiling ? room.stretchCeilingOffset : 0,
    outletWidth: room.outletWidth,
    outletHeight: room.outletHeight,
    selectedIds,
    onSelectElement: handleSelectElement,
    onStageRef,
    onUpdateElectrical: handleUpdateElectrical,
    onUpdateOpening: handleUpdateOpening,
    onUpdateAnnotation: handleUpdateAnnotation,
    onEditAnnotation: handleEditAnnotation,
    onPlaceElectrical: handlePlaceElectrical,
    onPlaceAnnotation: handlePlaceAnnotation,
    showMeasurements: layerVisibility.measurements,
    activeTool,
    selectedElectricalType,
  } as const;

  const panelClassName = fullView
    ? `${styles.panel} ${styles.panelFullView}`
    : `${styles.panel} ${isCollapsed ? styles.panelCollapsed : styles.panelExpanded}`;

  const isContentVisible = fullView || !isCollapsed;

  return (
    <div className={panelClassName}>
      {/* Header — hidden in full-view mode (no collapse needed) */}
      {!fullView && (
        <div className={styles.header} onClick={handleToggleCollapse}>
          <div className={styles.headerLeft}>
            <span
              className={`${styles.collapseIcon} ${isCollapsed ? '' : styles.collapseIconOpen}`}
            >
              &#9660;
            </span>
            <span className={styles.headerTitle}>{t('projection.title')}</span>
          </div>
          {!isCollapsed && (
            <button
              className={styles.layoutToggle}
              onClick={(e) => {
                e.stopPropagation();
                handleToggleLayout();
              }}
            >
              {layoutMode === 'tabs' ? t('projection.grid') : t('projection.tabs')}
            </button>
          )}
        </div>
      )}

      {/* Layout toggle in full-view mode (inline bar instead of collapsible header) */}
      {fullView && (
        <div className={styles.fullViewToolbar}>
          <button
            className={styles.layoutToggle}
            onClick={handleToggleLayout}
          >
            {layoutMode === 'tabs' ? t('projection.grid') : t('projection.tabs')}
          </button>
        </div>
      )}

      {isContentVisible && (
        <>
          {/* Tabs (only in tab mode) */}
          {layoutMode === 'tabs' && (
            <div className={styles.tabs}>
              {walls.map((wall, idx) => (
                <button
                  key={wall.id}
                  className={`${styles.tab} ${idx === clampedIndex ? styles.tabActive : ''}`}
                  onClick={() => setActiveWallIndex(idx)}
                >
                  {t(wallDirectionKey(wall))}
                </button>
              ))}
            </div>
          )}

          {/* Content area */}
          {layoutMode === 'tabs' ? (
            <div ref={contentRef} className={styles.content}>
              {walls[clampedIndex] ? (
                <div className={styles.viewContainer}>
                  <WallProjectionView
                    wall={walls[clampedIndex]}
                    {...sharedProps}
                    isHighlighted={walls[clampedIndex].id === highlightedWallId}
                    width={contentSize.width}
                    height={contentSize.height}
                  />
                </div>
              ) : (
                <div className={styles.emptyState}>{t('projection.noWall')}</div>
              )}
            </div>
          ) : (
            <div ref={contentRef} className={styles.gridLayout}>
              {walls.slice(0, 4).map((wall) => (
                <div key={wall.id} className={styles.gridCell}>
                  <WallProjectionView
                    wall={wall}
                    {...sharedProps}
                    isHighlighted={wall.id === highlightedWallId}
                    width={Math.floor(contentSize.width / 2)}
                    height={Math.floor(contentSize.height / 2)}
                  />
                </div>
              ))}
              {walls.length < 4 &&
                Array.from({ length: 4 - walls.length }).map((_, i) => (
                  <div key={`empty-${i}`} className={styles.gridCell}>
                    <div className={styles.emptyState}>--</div>
                  </div>
                ))}
            </div>
          )}
        </>
      )}
      <TextPromptModal
        open={editingAnnotation != null}
        title={t('annotation.editPrompt')}
        initialValue={editingAnnotation?.text ?? ''}
        onConfirm={(value) => {
          if (editingAnnotation && value !== editingAnnotation.text) {
            updateAnnotation({ ...editingAnnotation, text: value });
          }
          setEditingAnnotationId(null);
        }}
        onCancel={() => setEditingAnnotationId(null)}
      />
    </div>
  );
}
