import { memo, useMemo } from 'react';
import { Group, Rect, Line } from 'react-konva';
import type { Point, FurnitureItem } from '@house-plan-maker/shared';
import { rotatedAnchorOffsetToCenter } from '@house-plan-maker/shared';
import { BedSilhouette } from '../symbols/furniture/BedSilhouette';
import { DeskSilhouette } from '../symbols/furniture/DeskSilhouette';
import { WardrobeSilhouette } from '../symbols/furniture/WardrobeSilhouette';
import { SofaSilhouette } from '../symbols/furniture/SofaSilhouette';
import { TableSilhouette } from '../symbols/furniture/TableSilhouette';
import { ChairSilhouette } from '../symbols/furniture/ChairSilhouette';
import { ShelfSilhouette } from '../symbols/furniture/ShelfSilhouette';
import { TvSilhouette } from '../symbols/furniture/TvSilhouette';
import { findCollidingFurniture } from '../utils/collisionDetection';

interface FurnitureLayerProps {
  readonly items: readonly FurnitureItem[];
  readonly zoom: number;
  readonly panOffset: Point;
  readonly selectedIds: ReadonlySet<string>;
  readonly visible?: boolean;
  /** Global multiplier applied to every furniture item's opacity. */
  readonly globalOpacity?: number;
}

const FURNITURE_COLOR = '#495057';
const FURNITURE_FILL = 'rgba(222, 226, 230, 0.5)';
const SELECTED_COLOR = '#4c6ef5';
const SELECTED_FILL = 'rgba(76, 110, 245, 0.1)';
const COLLISION_COLOR = '#e03131';
const COLLISION_FILL = 'rgba(224, 49, 49, 0.1)';

function toScreen(point: Point, zoom: number, panOffset: Point): { x: number; y: number } {
  return {
    x: point.x * zoom + panOffset.x,
    y: point.y * zoom + panOffset.y,
  };
}

export const FurnitureLayer = memo(function FurnitureLayer({
  items,
  zoom,
  panOffset,
  selectedIds,
  visible = true,
  globalOpacity = 1,
}: FurnitureLayerProps) {
  const collidingIds = useMemo(() => findCollidingFurniture(items), [items]);

  return (
    <Group listening={false} visible={visible}>
      {items.map((item) => {
        // (x, y) is the anchored point on the ROTATED visual; convert to
        // bounding-box center using the rotation-aware helper so "left"
        // tracks the visual left edge regardless of how the item is
        // rotated. Reduces to (0, 0) for the default middle/middle anchor.
        const offset = rotatedAnchorOffsetToCenter(
          item.positionAnchor,
          item.width,
          item.depth,
          item.rotation,
        );
        const centerX = item.x + offset.dx;
        const centerY = item.y + offset.dy;
        const screenCenter = toScreen({ x: centerX, y: centerY }, zoom, panOffset);
        const isSelected = selectedIds.has(item.id);
        const isColliding = collidingIds.has(item.id);
        const widthPx = item.width * zoom;
        const depthPx = item.depth * zoom;

        const color = isColliding ? COLLISION_COLOR : isSelected ? SELECTED_COLOR : FURNITURE_COLOR;
        const fillColor = isColliding ? COLLISION_FILL : isSelected ? SELECTED_FILL : FURNITURE_FILL;

        const opacity = (item.opacity ?? 1) * globalOpacity;
        return (
          <Group key={item.id} opacity={opacity}>
            {renderFurnitureSilhouette(
              item.type,
              screenCenter.x,
              screenCenter.y,
              widthPx,
              depthPx,
              item.rotation,
              color,
              fillColor,
            )}
            {/* Rotation handle indicator for selected furniture */}
            {isSelected && (
              <RotationHandle
                x={screenCenter.x}
                y={screenCenter.y}
                depthPx={depthPx}
                rotation={item.rotation}
              />
            )}
          </Group>
        );
      })}
    </Group>
  );
});

interface RotationHandleProps {
  readonly x: number;
  readonly y: number;
  readonly depthPx: number;
  readonly rotation: number;
}

function RotationHandle({ x, y, depthPx, rotation }: RotationHandleProps) {
  const handleOffset = depthPx / 2 + 12;
  const rad = (rotation * Math.PI) / 180;
  const hx = x - Math.sin(rad) * handleOffset;
  const hy = y - Math.cos(rad) * handleOffset;

  return (
    <Group>
      {/* Line from center to handle */}
      <Line
        points={[x, y, hx, hy]}
        stroke={SELECTED_COLOR}
        strokeWidth={1}
        dash={[3, 3]}
        listening={false}
      />
      {/* Handle circle */}
      <Rect
        x={hx - 4}
        y={hy - 4}
        width={8}
        height={8}
        fill={SELECTED_COLOR}
        cornerRadius={4}
        listening={false}
      />
    </Group>
  );
}

function renderFurnitureSilhouette(
  type: string,
  x: number,
  y: number,
  width: number,
  depth: number,
  rotation: number,
  color: string,
  fillColor: string,
): React.ReactNode {
  const props = { x, y, width, depth, rotation, color, fillColor };

  switch (type) {
    case 'BED':
      return <BedSilhouette {...props} />;
    case 'DESK':
      return <DeskSilhouette {...props} />;
    case 'WARDROBE':
      return <WardrobeSilhouette {...props} />;
    case 'SOFA':
      return <SofaSilhouette {...props} />;
    case 'TABLE':
      return <TableSilhouette {...props} />;
    case 'CHAIR':
      return <ChairSilhouette {...props} />;
    case 'SHELF':
    case 'BOOKCASE':
      return <ShelfSilhouette {...props} />;
    case 'NIGHTSTAND':
      return <DeskSilhouette {...props} />;
    case 'DRESSER':
      return <WardrobeSilhouette {...props} />;
    case 'TV':
      return <TvSilhouette {...props} />;
    default: {
      // Generic rectangle fallback for types without a custom silhouette
      // (OTHER, RADIATOR, WALL_COLLAGE, CURTAIN, …).
      //
      // Rotation MUST pivot around the item's center. Konva's `<Rect>`
      // rotates around its stored (x, y) — which is the top-left corner,
      // not the center — so a bare `<Rect x={cx-w/2} y={cy-d/2} rotation>`
      // pivots around the unrotated top-left corner and drifts away from
      // the hit-test box as the item rotates. Wrapping the Rect in a
      // `<Group>` at (cx, cy) with the rotation on the Group gives the
      // correct center-pivot behaviour (matching the custom silhouettes).
      return (
        <Group x={x} y={y} rotation={rotation} listening={false}>
          <Rect
            x={-width / 2}
            y={-depth / 2}
            width={width}
            height={depth}
            stroke={color}
            strokeWidth={1.5}
            fill={fillColor}
            listening={false}
          />
        </Group>
      );
    }
  }
}
