import React, { useEffect, useRef, useState, useCallback } from 'react';
import { DraggableWindow } from './DraggableWindow';

const CANVAS_SIZE = 300;
const DEFAULT_RANGE = 0.5; // AC units, ~120m

const RADAR_COLORS: Record<string, string> = {
  Monster: '#ff4444', Player: '#4488ff', NPC: '#44cc44', Vendor: '#44cc44',
  Portal: '#aa44ff', Corpse: '#ff8800', Container: '#cccc44', Door: '#888888',
};

function compassDir(angleDeg: number): string {
  const a = ((angleDeg % 360) + 360) % 360;
  const dirs = ['N','NE','E','SE','S','SW','W','NW'];
  return dirs[Math.round(a / 45) % 8];
}

interface NearbyObject {
  id: number; name: string; object_class?: string; type?: string;
  ew?: number; ns?: number; distance?: number; bearing?: number;
  raw_x?: number; raw_y?: number;
  _px?: number; _py?: number;
}

interface Props {
  id: string; charName: string; zIndex: number;
  socket: WebSocket | null;
  radarData: any; // full nearby_objects message
}

export const RadarWindow: React.FC<Props> = ({ id, charName, zIndex, socket, radarData }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const rangeRef = useRef(DEFAULT_RANGE);
  const [range, setRange] = useState(DEFAULT_RANGE);
  const [selectedId, setSelectedId] = useState<number | null>(null);
  const mapImgRef = useRef<HTMLImageElement | null>(null);
  const objectsRef = useRef<NearbyObject[]>([]);

  // Load map image once
  useEffect(() => {
    const img = new Image();
    img.src = '/dereth.png';
    img.onload = () => { mapImgRef.current = img; };
  }, []);

  // Send start_radar on open, stop_radar on close
  useEffect(() => {
    if (socket?.readyState === WebSocket.OPEN) {
      socket.send(JSON.stringify({ player_name: charName, command: 'start_radar' }));
    }
    return () => {
      if (socket?.readyState === WebSocket.OPEN) {
        socket.send(JSON.stringify({ player_name: charName, command: 'stop_radar' }));
      }
    };
  }, [charName, socket]);

  // Scroll to zoom
  const handleWheel = useCallback((e: React.WheelEvent) => {
    e.preventDefault();
    const factor = e.deltaY > 0 ? 1.25 : 0.8;
    rangeRef.current = Math.max(0.02, Math.min(5.0, rangeRef.current * factor));
    setRange(rangeRef.current);
  }, []);

  // Click to select
  const handleCanvasClick = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const rect = canvas.getBoundingClientRect();
    const mx = (e.clientX - rect.left) * (canvas.width / rect.width);
    const my = (e.clientY - rect.top) * (canvas.height / rect.height);
    let closestObj: NearbyObject | null = null;
    let closestDist = 20;
    objectsRef.current.forEach(obj => {
      if (obj._px === undefined) return;
      const d = Math.sqrt((mx - obj._px) ** 2 + (my - obj._py!) ** 2);
      if (d < closestDist) { closestDist = d; closestObj = obj; }
    });
    setSelectedId(closestObj ? (closestObj as NearbyObject).id : null);
  }, []);

  // Render canvas
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas || !radarData) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const size = CANVAS_SIZE;
    const cx = size / 2, cy = size / 2;
    const objects: NearbyObject[] = radarData.objects ?? [];
    const playerEW = radarData.player_ew ?? 0;
    const playerNS = radarData.player_ns ?? 0;
    const heading = radarData.player_heading ?? 0;
    const isDungeon = radarData.is_dungeon ?? false;
    const playerX = radarData.player_x ?? 0;
    const playerY = radarData.player_y ?? 0;
    const currentRange = rangeRef.current;
    const scale = isDungeon ? (size / 2) / (currentRange * 240) : (size / 2) / currentRange;
    const headingRad = heading * Math.PI / 180;

    // Clear + dark circle background
    ctx.clearRect(0, 0, size, size);
    ctx.fillStyle = '#111';
    ctx.beginPath();
    ctx.arc(cx, cy, cx, 0, Math.PI * 2);
    ctx.fill();

    // Clip to circle
    ctx.save();
    ctx.beginPath();
    ctx.arc(cx, cy, cx - 1, 0, Math.PI * 2);
    ctx.clip();

    // Semi-transparent map background (overworld)
    if (!isDungeon && mapImgRef.current) {
      const mapImg = mapImgRef.current;
      const pixPerCoord = mapImg.naturalWidth / 204.2;
      const mapCenterX = (playerEW + 102.1) * pixPerCoord;
      const mapCenterY = (102.1 - playerNS) * pixPerCoord;
      ctx.globalAlpha = 0.4;
      ctx.save();
      ctx.translate(cx, cy);
      ctx.rotate(-headingRad);
      ctx.drawImage(mapImg,
        mapCenterX - (cx / scale) * pixPerCoord,
        mapCenterY - (cy / scale) * pixPerCoord,
        (size / scale) * pixPerCoord,
        (size / scale) * pixPerCoord,
        -cx, -cy, size, size);
      ctx.restore();
      ctx.globalAlpha = 1.0;
    }

    ctx.restore();

    // Range rings (4)
    ctx.strokeStyle = '#333';
    ctx.lineWidth = 1;
    for (let i = 1; i <= 4; i++) {
      ctx.beginPath();
      ctx.arc(cx, cy, (cx / 4) * i, 0, Math.PI * 2);
      ctx.stroke();
    }

    // Crosshairs
    ctx.beginPath();
    ctx.moveTo(cx, 0); ctx.lineTo(cx, size);
    ctx.moveTo(0, cy); ctx.lineTo(size, cy);
    ctx.stroke();

    // Compass labels
    ctx.font = 'bold 12px monospace';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    [{ l: 'N', a: 0 }, { l: 'E', a: Math.PI / 2 }, { l: 'S', a: Math.PI }, { l: 'W', a: -Math.PI / 2 }].forEach(({ l, a }) => {
      const ra = a - headingRad;
      ctx.fillStyle = l === 'N' ? '#cc4444' : '#888';
      ctx.fillText(l, cx + Math.sin(ra) * (cx - 12), cy - Math.cos(ra) * (cx - 12));
    });

    // Facing line
    ctx.strokeStyle = '#666';
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(cx, cy);
    ctx.lineTo(cx, cy - cx * 0.85);
    ctx.stroke();

    // Entity dots
    const rotAngle = isDungeon ? (Math.PI - headingRad) : headingRad;
    const cosA = Math.cos(rotAngle), sinA = Math.sin(rotAngle);

    objects.forEach(obj => {
      let dX: number, dY: number;
      if (isDungeon && obj.raw_x !== undefined) {
        dX = -(obj.raw_x - playerX);
        dY = (obj.raw_y! - playerY);
      } else {
        dX = (obj.ew ?? 0) - playerEW;
        dY = (obj.ns ?? 0) - playerNS;
      }
      const dx = dX * cosA - dY * sinA;
      const dy = isDungeon ? (dX * sinA + dY * cosA) : -(dX * sinA + dY * cosA);
      const px = cx + dx * scale;
      const py = cy + dy * scale;

      const distFromCenter = Math.sqrt((px - cx) ** 2 + (py - cy) ** 2);
      if (distFromCenter > cx - 4) return;

      obj._px = px;
      obj._py = py;

      const objClass = obj.object_class ?? obj.type ?? '';
      const color = RADAR_COLORS[objClass] ?? '#888';
      const isSel = obj.id === selectedId;
      const dotSize = isSel ? 6 : (objClass === 'Monster' || objClass === 'Player') ? 4 : 3;

      if (isSel) {
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.arc(px, py, dotSize + 3, 0, Math.PI * 2);
        ctx.stroke();
      }

      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.arc(px, py, dotSize, 0, Math.PI * 2);
      ctx.fill();

      if (objClass === 'Player' || objClass === 'Portal' || isSel) {
        ctx.fillStyle = isSel ? '#fff' : color;
        ctx.font = '9px monospace';
        ctx.textAlign = 'left';
        ctx.fillText(obj.name, px + 6, py + 3);
      }
    });

    objectsRef.current = objects;

    // Player dot (center)
    ctx.fillStyle = '#ffcc00';
    ctx.beginPath();
    ctx.arc(cx, cy, 5, 0, Math.PI * 2);
    ctx.fill();
    ctx.strokeStyle = '#fff';
    ctx.lineWidth = 1;
    ctx.stroke();
  }, [radarData, range, selectedId]);

  // Entity list with distance + direction
  const entities = (radarData?.objects ?? []).map((obj: any) => {
    const pEW = radarData?.player_ew ?? 0;
    const pNS = radarData?.player_ns ?? 0;
    const isDungeon = radarData?.is_dungeon ?? false;
    const pX = radarData?.player_x ?? 0;
    const pY = radarData?.player_y ?? 0;
    let dX: number, dY: number, dist: number;
    if (isDungeon && obj.raw_x !== undefined) {
      dX = -(obj.raw_x - pX); dY = obj.raw_y - pY;
      dist = Math.sqrt(dX * dX + dY * dY);
    } else {
      dX = (obj.ew ?? 0) - pEW; dY = (obj.ns ?? 0) - pNS;
      dist = Math.sqrt(dX * dX + dY * dY) * 240;
    }
    const angle = Math.atan2(dX, dY) * 180 / Math.PI;
    return { ...obj, dist, dir: compassDir(angle) };
  }).sort((a: any, b: any) => a.dist - b.dist);

  const rangeMeters = Math.round(range * 240);

  return (
    <DraggableWindow id={id} title={`Radar: ${charName}`} zIndex={zIndex} width={360} height={560}>
      {/* Controls */}
      <div style={{ padding: '4px 8px', display: 'flex', justifyContent: 'space-between', fontSize: '0.75rem', color: '#888', borderBottom: '1px solid #333', background: '#1a1a1a' }}>
        <span>Range: ~{rangeMeters}m</span>
        <span style={{ fontSize: '0.65rem', color: '#555' }}>Scroll to zoom</span>
      </div>

      {/* Canvas */}
      <canvas ref={canvasRef} width={CANVAS_SIZE} height={CANVAS_SIZE}
        style={{ display: 'block', margin: '0 auto', borderBottom: '1px solid #333', cursor: 'crosshair', flexShrink: 0 }}
        onWheel={handleWheel} onClick={handleCanvasClick} />

      {/* Entity list */}
      <div style={{ flex: 1, overflowY: 'auto', fontSize: '0.72rem', minHeight: 0 }}>
        {/* Header */}
        <div style={{ display: 'flex', padding: '3px 6px', borderBottom: '1px solid #333', color: '#666', fontSize: '0.65rem', fontWeight: 600 }}>
          <span style={{ width: 8 }}></span>
          <span style={{ flex: 1, marginLeft: 6 }}>Name</span>
          <span style={{ width: 55, textAlign: 'left' }}>Type</span>
          <span style={{ width: 40, textAlign: 'right' }}>Dist</span>
          <span style={{ width: 24, textAlign: 'center' }}>Dir</span>
        </div>
        {entities.length === 0 && (
          <div style={{ padding: 12, color: '#555', textAlign: 'center', fontSize: '0.7rem' }}>
            Waiting for radar data...
          </div>
        )}
        {entities.map((obj: any) => {
          const objClass = obj.object_class ?? obj.type ?? '';
          const color = RADAR_COLORS[objClass] ?? '#888';
          const isSel = obj.id === selectedId;
          return (
            <div key={obj.id} onClick={() => setSelectedId(isSel ? null : obj.id)}
              style={{
                display: 'flex', alignItems: 'center', padding: '2px 6px',
                borderBottom: '1px solid #1a1a1a', cursor: 'pointer', color: '#ccc',
                background: isSel ? '#1a2a3a' : '', borderLeft: isSel ? '2px solid #4488ff' : '2px solid transparent',
              }}>
              <span style={{ width: 8, height: 8, borderRadius: '50%', background: color, flexShrink: 0 }}></span>
              <span style={{ flex: 1, marginLeft: 6, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{obj.name}</span>
              <span style={{ width: 55, color: '#888', fontSize: '0.65rem' }}>{objClass}</span>
              <span style={{ width: 40, textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>
                {obj.dist < 1000 ? `${Math.round(obj.dist)}m` : `${(obj.dist / 1000).toFixed(1)}km`}
              </span>
              <span style={{ width: 24, textAlign: 'center', color: '#666' }}>{obj.dir}</span>
            </div>
          );
        })}
      </div>
    </DraggableWindow>
  );
};
