'use client';

import React from 'react';

import type { OfficeMemberView, OfficeTaskStatus, OfficeView, OfficeZoneId } from '@/lib/office';
import { cn } from '@/lib/utils';

type ZoneLayout = {
  x: number;
  y: number;
  width: number;
  height: number;
};

const WORLD_WIDTH = 400;
const WORLD_HEIGHT = 225;
const RENDER_SCALE = 2;
const SCENE_WIDTH = WORLD_WIDTH * RENDER_SCALE;
const SCENE_HEIGHT = WORLD_HEIGHT * RENDER_SCALE;
const TILE_SIZE = 16;
const MAP_KEY = 'office-winter-v1';
const TILESET_KEY = 'office-winter-tileset';
const MAP_PATH = '/office/maps/office-winter-v1.tmj';
const TILESET_PATH = '/office/tiles/office-winter-tileset.png';
const PIXEL_AGENTS_BASE = '/office/vendor/pixel-agents/assets';

const FURNITURE_ASSETS = {
  deskFront: { key: 'pixel-agents-desk-front', path: `${PIXEL_AGENTS_BASE}/furniture/DESK/DESK_FRONT.png` },
  chairFront: { key: 'pixel-agents-chair-front', path: `${PIXEL_AGENTS_BASE}/furniture/WOODEN_CHAIR/WOODEN_CHAIR_FRONT.png` },
  sofaFront: { key: 'pixel-agents-sofa-front', path: `${PIXEL_AGENTS_BASE}/furniture/SOFA/SOFA_FRONT.png` },
  tableFront: { key: 'pixel-agents-table-front', path: `${PIXEL_AGENTS_BASE}/furniture/TABLE_FRONT/TABLE_FRONT.png` },
  coffeeTable: { key: 'pixel-agents-coffee-table', path: `${PIXEL_AGENTS_BASE}/furniture/COFFEE_TABLE/COFFEE_TABLE.png` },
  doubleBookshelf: { key: 'pixel-agents-double-bookshelf', path: `${PIXEL_AGENTS_BASE}/furniture/DOUBLE_BOOKSHELF/DOUBLE_BOOKSHELF.png` },
  pcOn: { key: 'pixel-agents-pc-on', path: `${PIXEL_AGENTS_BASE}/furniture/PC/PC_FRONT_ON_1.png` },
  whiteboard: { key: 'pixel-agents-whiteboard', path: `${PIXEL_AGENTS_BASE}/furniture/WHITEBOARD/WHITEBOARD.png` },
} as const;

const CHARACTER_ASSETS = [
  { key: 'pixel-agent-char-0', path: `${PIXEL_AGENTS_BASE}/characters/char_0.png` },
  { key: 'pixel-agent-char-1', path: `${PIXEL_AGENTS_BASE}/characters/char_1.png` },
  { key: 'pixel-agent-char-2', path: `${PIXEL_AGENTS_BASE}/characters/char_2.png` },
  { key: 'pixel-agent-char-3', path: `${PIXEL_AGENTS_BASE}/characters/char_3.png` },
  { key: 'pixel-agent-char-4', path: `${PIXEL_AGENTS_BASE}/characters/char_4.png` },
  { key: 'pixel-agent-char-5', path: `${PIXEL_AGENTS_BASE}/characters/char_5.png` },
] as const;

const CHARACTER_FRAME = {
  width: 16,
  height: 24,
  columnsPerRow: 7,
  frontRow: 0,
  idleColumns: [0, 1, 2],
};

const ZONE_LAYOUTS: Record<OfficeZoneId, ZoneLayout> = {
  reception: { x: 144, y: 28, width: 68, height: 40 },
  workspace: { x: 32, y: 28, width: 86, height: 100 },
  collab: { x: 152, y: 118, width: 104, height: 62 },
  research: { x: 272, y: 28, width: 66, height: 66 },
  alert: { x: 284, y: 92, width: 52, height: 54 },
  done: { x: 30, y: 154, width: 76, height: 40 },
};

const STATUS_TONES: Record<
  OfficeTaskStatus,
  { body: number; outline: number; lamp: number; badge: number; badgeText: string; text: string }
> = {
  queued: { body: 0x8aa0b8, outline: 0xe8f0f8, lamp: 0xcbd5e1, badge: 0x31425b, badgeText: 'Q', text: '#e8f0f8' },
  running: { body: 0x90caf9, outline: 0xf5faff, lamp: 0xfff59d, badge: 0x4a5a72, badgeText: 'R', text: '#f5faff' },
  waiting: { body: 0xd8c79a, outline: 0xfff7ed, lamp: 0xfde68a, badge: 0x7c6843, badgeText: 'W', text: '#fff7ed' },
  blocked: { body: 0xd96c75, outline: 0xffe4e6, lamp: 0xffab91, badge: 0x7b3340, badgeText: '!', text: '#fff1f2' },
  done: { body: 0x78c27a, outline: 0xe8f5e9, lamp: 0xc5e1a5, badge: 0x44664b, badgeText: 'D', text: '#f0fdf4' },
  error: { body: 0xf36d7d, outline: 0xffd1dc, lamp: 0xffab91, badge: 0x7b2634, badgeText: 'X', text: '#fff1f2' },
  cancelled: { body: 0x6b7280, outline: 0xe5e7eb, lamp: 0xd1d5db, badge: 0x374151, badgeText: 'S', text: '#f3f4f6' },
};

function groupMembersByZone(members: OfficeMemberView[]) {
  const grouped = new Map<OfficeZoneId, OfficeMemberView[]>();

  for (const member of members) {
    const bucket = grouped.get(member.zoneId);
    if (bucket) {
      bucket.push(member);
    } else {
      grouped.set(member.zoneId, [member]);
    }
  }

  return grouped;
}

function zoneGridPoints(layout: ZoneLayout, count: number) {
  if (count <= 0) return [];

  const innerLeft = layout.x + 12;
  const innerTop = layout.y + 14;
  const innerWidth = Math.max(layout.width - 24, 10);
  const innerHeight = Math.max(layout.height - 20, 10);
  const columns = count <= 2 ? count : count <= 4 ? 2 : 3;
  const rows = Math.ceil(count / columns);
  const points: Array<{ x: number; y: number }> = [];

  for (let index = 0; index < count; index += 1) {
    const column = index % columns;
    const row = Math.floor(index / columns);
    const x = innerLeft + ((column + 0.5) * innerWidth) / columns;
    const y = innerTop + ((row + 0.5) * innerHeight) / rows;
    points.push({ x: Math.round(x), y: Math.round(y) });
  }

  return points;
}

function buildMemberPositions(office: OfficeView) {
  const grouped = groupMembersByZone(office.members);
  const positions = new Map<string, { x: number; y: number }>();

  for (const zone of office.zones) {
    const layout = ZONE_LAYOUTS[zone.id];
    const members = grouped.get(zone.id) ?? [];
    const points = zoneGridPoints(layout, members.length);
    members.forEach((member, index) => {
      positions.set(member.currentRunId, points[index] ?? { x: layout.x + 20, y: layout.y + 20 });
    });
  }

  return positions;
}

function truncateLabel(value: string, maxLength: number) {
  if (value.length <= maxLength) return value;
  return `${value.slice(0, Math.max(1, maxLength - 1))}…`;
}

function pickCharacterAsset(member: OfficeMemberView, index: number) {
  if (member.isPrimary) return CHARACTER_ASSETS[0];
  return CHARACTER_ASSETS[(index % (CHARACTER_ASSETS.length - 1)) + 1];
}

function resolveCharacterPose() {
  return {
    row: CHARACTER_FRAME.frontRow,
    columns: CHARACTER_FRAME.idleColumns,
    interval: 220,
  };
}

function addFurnitureSprite(scene: any, object: any) {
  const x = object.x ?? 0;
  const y = object.y ?? 0;
  const width = object.width ?? TILE_SIZE;
  const height = object.height ?? TILE_SIZE;
  const centerX = x + width / 2;
  const type = object.type ?? 'anchor';

  const addImage = (assetKey: string, px: number, py: number, depth = 20) =>
    scene.add.image(px, py, assetKey).setOrigin(0.5, 1).setDepth(depth);

  if (type === 'desk-anchor') {
    const desk = addImage(FURNITURE_ASSETS.deskFront.key, centerX, y + height + 4);
    const pc = addImage(FURNITURE_ASSETS.pcOn.key, centerX, y + height + 2, 21);
    return [desk, pc];
  }

  if (type === 'chair-anchor') return [addImage(FURNITURE_ASSETS.chairFront.key, centerX, y + height + 1)];
  if (type === 'sofa-anchor') return [addImage(FURNITURE_ASSETS.sofaFront.key, centerX, y + height)];
  if (type === 'coffee-anchor') return [addImage(FURNITURE_ASSETS.coffeeTable.key, centerX, y + height)];
  if (type === 'meeting-anchor') return [addImage(FURNITURE_ASSETS.tableFront.key, centerX, y + height + 16)];
  if (type === 'server-anchor') return [addImage(FURNITURE_ASSETS.doubleBookshelf.key, centerX, y + height)];
  if (type === 'archive-anchor') return [addImage(FURNITURE_ASSETS.doubleBookshelf.key, centerX, y + height)];
  if (type === 'whiteboard-anchor') return [addImage(FURNITURE_ASSETS.whiteboard.key, centerX, y + height)];

  return [];
}

export function OfficePhaserCanvas({
  office,
  selectedRunId,
  onRunSelect,
  className,
  showMetaBar = true,
}: {
  office: OfficeView;
  selectedRunId: string | null;
  onRunSelect: (runId: string) => void;
  className?: string;
  showMetaBar?: boolean;
}) {
  const containerRef = React.useRef<HTMLDivElement | null>(null);
  const selectRef = React.useRef(onRunSelect);

  React.useEffect(() => {
    selectRef.current = onRunSelect;
  }, [onRunSelect]);

  React.useEffect(() => {
    let destroyed = false;
    let game: any = null;

    async function mountScene() {
      if (!containerRef.current) return;

      const PhaserImport = await import('phaser');
      const Phaser = (PhaserImport.default ?? PhaserImport) as any;
      if (destroyed || !containerRef.current) return;

      const memberPositions = buildMemberPositions(office);
      class OfficeScene extends Phaser.Scene {
        preload(this: any) {
          if (!this.textures.exists(TILESET_KEY)) {
            this.load.image(TILESET_KEY, TILESET_PATH);
          }
          if (!this.cache.tilemap.exists(MAP_KEY)) {
            this.load.tilemapTiledJSON(MAP_KEY, MAP_PATH);
          }

          Object.values(FURNITURE_ASSETS).forEach((asset) => {
            if (!this.textures.exists(asset.key)) {
              this.load.image(asset.key, asset.path);
            }
          });

          CHARACTER_ASSETS.forEach((asset) => {
            if (!this.textures.exists(asset.key)) {
              this.load.spritesheet(asset.key, asset.path, {
                frameWidth: CHARACTER_FRAME.width,
                frameHeight: CHARACTER_FRAME.height,
              });
            }
          });
        }

        create(this: any) {
          this.cameras.main.setBackgroundColor('#1a2433');
          this.cameras.main.roundPixels = true;
          this.cameras.main.setZoom(RENDER_SCALE);
          this.cameras.main.setBounds(0, 0, WORLD_WIDTH, WORLD_HEIGHT);

          const map = this.make.tilemap({ key: MAP_KEY });
          const tileset = map.addTilesetImage('office-winter-tileset', TILESET_KEY, TILE_SIZE, TILE_SIZE, 0, 0);
          if (!tileset) {
            throw new Error('Failed to load office-winter-tileset into tilemap');
          }

          ['bg-floor', 'bg-rug', 'walls', 'windows', 'markers'].forEach((layerName, index) => {
            const layer = map.createLayer(layerName, tileset, 0, 0);
            layer?.setDepth(index);
          });

          const frame = this.add.rectangle(0, 0, WORLD_WIDTH, WORLD_HEIGHT, 0x000000, 0).setOrigin(0, 0);
          frame.setStrokeStyle(4, 0x101827, 1);
          frame.setDepth(10);

          const objectLayer = map.getObjectLayer('furniture-anchors');
          objectLayer?.objects.forEach((object: any) => {
            const placed = addFurnitureSprite(this, object);
            if (placed.length > 0) return;

            const x = object.x ?? 0;
            const y = object.y ?? 0;
            const width = object.width ?? TILE_SIZE;
            const height = object.height ?? TILE_SIZE;
            const fallback = this.add.rectangle(x, y, width, height, 0x384b69, 0.18).setOrigin(0, 0);
            fallback.setStrokeStyle(2, 0x90caf9, 0.9);
            fallback.setDepth(20);
          });

          const assignmentLines = this.add.graphics();
          assignmentLines.setDepth(50);
          office.assignments.forEach((assignment) => {
            const from = memberPositions.get(assignment.ownerRunId);
            if (!from) return;

            assignment.assigneeRunIds.forEach((assigneeRunId) => {
              const to = memberPositions.get(assigneeRunId);
              if (!to) return;

              assignmentLines.lineStyle(1, 0xffd166, 0.75);
              assignmentLines.beginPath();
              assignmentLines.moveTo(from.x, from.y);
              assignmentLines.lineTo(to.x, to.y);
              assignmentLines.strokePath();
              assignmentLines.fillStyle(0xffd166, 1);
              assignmentLines.fillRect(to.x - 1, to.y - 1, 2, 2);
            });
          });

          office.members.forEach((member, memberIndex) => {
            const point = memberPositions.get(member.currentRunId);
            if (!point) return;

            const tone = STATUS_TONES[member.status];
            const isSelected = selectedRunId === member.currentRunId;
            const isPrimary = member.isPrimary;
            const container = this.add.container(point.x, point.y);
            container.setDepth(60);

            const clickTarget = this.add.rectangle(0, 0, isPrimary ? 34 : 30, isPrimary ? 36 : 32, 0x000000, 0.001);
            clickTarget.setInteractive({ useHandCursor: true });
            clickTarget.setOrigin(0.5);

            const shadow = this.add.rectangle(0, 9, isPrimary ? 15 : 13, 4, 0x0f172a, 0.7);
            shadow.setOrigin(0.5);

            const characterAsset = pickCharacterAsset(member, memberIndex);
            const pose = resolveCharacterPose();
            let frameIndex = 0;

            const character = this.add
              .sprite(0, 4, characterAsset.key, 0)
              .setDisplaySize(isPrimary ? 24 : 21, isPrimary ? 36 : 32)
              .setOrigin(0.5, 1);

            const applyCharacterFrame = () => {
              const column = pose.columns[frameIndex % pose.columns.length] ?? pose.columns[0] ?? 0;
              const frame = pose.row * CHARACTER_FRAME.columnsPerRow + column;
              character.setFrame(frame);
              frameIndex += 1;
            };

            applyCharacterFrame();
            this.time.addEvent({
              delay: pose.interval,
              loop: true,
              callback: applyCharacterFrame,
            });

            const highlight = this.add.rectangle(0, -9, isPrimary ? 14 : 12, 19, tone.body, 0.12);
            highlight.setStrokeStyle(isSelected ? 2 : 1, isSelected ? 0xfef3c7 : tone.outline, isSelected ? 1 : 0.7);
            highlight.setOrigin(0.5);

            const lamp = this.add.rectangle(isPrimary ? 8 : 7, -9, 3, 3, tone.lamp, 1);
            lamp.setStrokeStyle(1, 0x101827, 1);
            lamp.setOrigin(0.5);

            const badge = this.add.rectangle(0, -14, isPrimary ? 12 : 10, 5, isPrimary ? 0xffd166 : tone.badge, 1);
            badge.setStrokeStyle(1, 0x101827, 1);
            badge.setOrigin(0.5);

            const badgeText = this.add
              .text(0, -16.5, isPrimary ? 'M' : tone.badgeText, {
                color: isPrimary ? '#1a2433' : tone.text,
                fontFamily: '"Courier New", monospace',
                fontSize: '5px',
                fontStyle: 'bold',
              })
              .setOrigin(0.5, 0);

            const name = this.add
              .text(0, 14, truncateLabel(member.actorName.toUpperCase(), isPrimary ? 10 : 8), {
                color: '#f5faff',
                fontFamily: '"Courier New", monospace',
                fontSize: isPrimary ? '5px' : '4px',
                fontStyle: 'bold',
                align: 'center',
              })
              .setOrigin(0.5, 0);

            const taskLabel = this.add
              .text(0, 20, truncateLabel((member.stageLabel ?? member.currentTitle).toUpperCase(), 12), {
                color: '#cbd5e1',
                fontFamily: '"Courier New", monospace',
                fontSize: '4px',
                align: 'center',
              })
              .setOrigin(0.5, 0);

            container.add([clickTarget, shadow, highlight, badge, badgeText, character, lamp, name, taskLabel]);

            clickTarget.on('pointerdown', () => {
              selectRef.current(member.currentRunId);
            });

            clickTarget.on('pointerover', () => {
              this.tweens.add({ targets: container, scaleX: 1.08, scaleY: 1.08, duration: 90 });
            });

            clickTarget.on('pointerout', () => {
              this.tweens.add({ targets: container, scaleX: 1, scaleY: 1, duration: 90 });
            });

            if (member.status === 'running') {
              this.tweens.add({
                targets: container,
                y: point.y - 1.5,
                duration: 500,
                yoyo: true,
                repeat: -1,
                ease: 'Sine.easeInOut',
              });
              this.tweens.add({
                targets: lamp,
                alpha: 0.2,
                duration: 180,
                yoyo: true,
                repeat: -1,
              });
            }

            if (member.status === 'blocked' || member.status === 'error') {
              const warn = this.add
                .text(isPrimary ? 8 : 7, -3, '!', {
                  color: '#fff7ed',
                  fontFamily: '"Courier New", monospace',
                  fontSize: '8px',
                  fontStyle: 'bold',
                })
                .setOrigin(0.5);
              container.add(warn);
              this.tweens.add({
                targets: warn,
                alpha: 0.25,
                duration: 180,
                yoyo: true,
                repeat: -1,
              });
            }

            if (member.status === 'done') {
              const doneMark = this.add.rectangle(isPrimary ? 7 : 6, 7, 3, 3, 0x78c27a, 1);
              doneMark.setStrokeStyle(1, 0xf0fdf4, 1);
              doneMark.setOrigin(0.5);
              container.add(doneMark);
            }
          });
        }
      }

      game = new Phaser.Game({
        type: Phaser.CANVAS,
        width: SCENE_WIDTH,
        height: SCENE_HEIGHT,
        parent: containerRef.current,
        pixelArt: true,
        antialias: false,
        roundPixels: true,
        backgroundColor: '#1a2433',
        scene: OfficeScene,
        scale: {
          mode: Phaser.Scale.FIT,
          autoCenter: Phaser.Scale.CENTER_BOTH,
        },
      });
    }

    mountScene().catch((error) => {
      console.error('Failed to mount Office Phaser canvas', error);
    });

    return () => {
      destroyed = true;
      game?.destroy(true);
    };
  }, [office, selectedRunId]);

  return (
    <div className={cn('space-y-3', className)}>
      {showMetaBar ? (
        <div className="flex flex-wrap items-center gap-2 text-[#cbd5e1]">
          <span className="rounded-none border-2 border-[#5a7092] bg-[#1a2433] px-3 py-1 text-[11px] font-semibold tracking-[0.2em] text-[#f5faff]">
            WINTER OFFICE MAP
          </span>
          <span className="rounded-none border-2 border-[#30364d] bg-[#171b29] px-3 py-1 text-[11px]">
            400 x 225 LOGIC / 800 x 450 RENDER
          </span>
          <span className="rounded-none border-2 border-[#30364d] bg-[#171b29] px-3 py-1 text-[11px]">
            {office.members.length} AGENTS
          </span>
          <span className="rounded-none border-2 border-[#30364d] bg-[#171b29] px-3 py-1 text-[11px]">
            {office.assignments.length} LINKS
          </span>
        </div>
      ) : null}

      <div className="overflow-hidden rounded-none border-4 border-[#0e1119] bg-[#171522] p-3 shadow-[0_0_0_2px_#2a223b_inset]">
        <div
          className="mx-auto w-full max-w-[1200px] overflow-hidden border-4 border-[#5a7092] bg-[#1a2433]"
          style={{ aspectRatio: `${WORLD_WIDTH} / ${WORLD_HEIGHT}` }}
        >
          <div
            ref={containerRef}
            className="h-full w-full [&_canvas]:!block [&_canvas]:!h-full [&_canvas]:!w-full [&_canvas]:image-rendering-[pixelated]"
          />
        </div>
      </div>
    </div>
  );
}
