import React, { useEffect, useState } from 'react';

import { AtlasTileSpec, buildMedievalNpcVisual, MedievalNpcVisualSpec } from '../data/medievalNpcVisuals';
import { Encounter } from '../types';
import {
  DEFAULT_NPC_LAYOUT_CONFIG,
  type NpcLayoutConfig,
  type NpcLayoutPart,
} from './npcVisualShared';

const TILE_SIZE = 32;
const HAND_TILE_SIZE = 16;
const IDLE_FRAME_MS = 140;

function mergeLayoutConfig(layoutConfig?: Partial<NpcLayoutConfig>): NpcLayoutConfig {
  if (!layoutConfig) return DEFAULT_NPC_LAYOUT_CONFIG;

  return {
    body: { ...DEFAULT_NPC_LAYOUT_CONFIG.body, ...layoutConfig.body },
    head: { ...DEFAULT_NPC_LAYOUT_CONFIG.head, ...layoutConfig.head },
    facialHair: { ...DEFAULT_NPC_LAYOUT_CONFIG.facialHair, ...layoutConfig.facialHair },
    hair: { ...DEFAULT_NPC_LAYOUT_CONFIG.hair, ...layoutConfig.hair },
    headgear: { ...DEFAULT_NPC_LAYOUT_CONFIG.headgear, ...layoutConfig.headgear },
    hand: { ...DEFAULT_NPC_LAYOUT_CONFIG.hand, ...layoutConfig.hand },
    mainHand: { ...DEFAULT_NPC_LAYOUT_CONFIG.mainHand, ...layoutConfig.mainHand },
    offHand: { ...DEFAULT_NPC_LAYOUT_CONFIG.offHand, ...layoutConfig.offHand },
  };
}

function LayerSprite({
  src,
  frameIndex,
  tileSize = TILE_SIZE,
  x = 0,
  y = 0,
  zIndex = 0,
}: {
  src: string;
  frameIndex: number;
  tileSize?: number;
  x?: number;
  y?: number;
  zIndex?: number;
}) {
  return (
    <div
      style={{
        position: 'absolute',
        left: `${x}px`,
        top: `${y}px`,
        width: `${tileSize}px`,
        height: `${tileSize}px`,
        backgroundImage: `url("${encodeURI(src)}")`,
        backgroundRepeat: 'no-repeat',
        backgroundPosition: `-${frameIndex * tileSize}px 0px`,
        imageRendering: 'pixelated',
        zIndex,
      }}
    />
  );
}

function AtlasSprite({
  spec,
  x = 0,
  y = 0,
  zIndex = 0,
}: {
  spec: AtlasTileSpec;
  x?: number;
  y?: number;
  zIndex?: number;
}) {
  const tileWidth = spec.tileWidth ?? TILE_SIZE;
  const tileHeight = spec.tileHeight ?? TILE_SIZE;
  const col = spec.frameIndex % spec.columns;
  const row = Math.floor(spec.frameIndex / spec.columns);

  return (
    <div
      style={{
        position: 'absolute',
        left: `${x - (tileWidth - TILE_SIZE) / 2 + (spec.renderOffsetX ?? 0)}px`,
        top: `${y - (tileHeight - TILE_SIZE) + (spec.renderOffsetY ?? 0)}px`,
        width: `${tileWidth}px`,
        height: `${tileHeight}px`,
        backgroundImage: `url("${encodeURI(spec.src)}")`,
        backgroundRepeat: 'no-repeat',
        backgroundPosition: `-${col * tileWidth}px -${row * tileHeight}px`,
        imageRendering: 'pixelated',
        zIndex,
      }}
    />
  );
}

export function MedievalNpcAnimator({
  encounter,
  visualSpec,
  layoutConfig,
  onPartPointerDown,
  selectedPart,
  className,
  scale = 2.4,
  facing = 'right',
}: {
  encounter?: Encounter;
  visualSpec?: MedievalNpcVisualSpec;
  layoutConfig?: Partial<NpcLayoutConfig>;
  onPartPointerDown?: (part: NpcLayoutPart, event: React.PointerEvent<HTMLDivElement>) => void;
  selectedPart?: NpcLayoutPart | null;
  className?: string;
  scale?: number;
  facing?: 'left' | 'right';
}) {
  const [frameCursor, setFrameCursor] = useState(0);
  const visual = visualSpec ?? buildMedievalNpcVisual(encounter ?? {
    npcName: '预览角色',
    npcDescription: '用于预览的角色外形。',
    npcAvatar: '预',
    context: '预览',
  });
  const bodyFrame = visual.bodyFrames[frameCursor % visual.bodyFrames.length] ?? 0;
  const headFrame = visual.headFrame;
  const hairFrame = visual.hairFrame;
  const handFrame = visual.handFrame;
  const facialFrame = visual.facialHairFrame ?? 0;
  const bobOffsets = [0, 1, 1, -1];
  const bobY = bobOffsets[frameCursor % bobOffsets.length] ?? 0;
  const layout = mergeLayoutConfig(layoutConfig);

  const getPartClassName = (part: NpcLayoutPart) =>
    onPartPointerDown
      ? `cursor-grab ${selectedPart === part ? 'drop-shadow-[0_0_10px_rgba(16,185,129,0.7)]' : ''}`
      : '';

  const getPartHandlers = (part: NpcLayoutPart) =>
    onPartPointerDown
      ? {
          onPointerDown: (event: React.PointerEvent<HTMLDivElement>) => onPartPointerDown(part, event),
        }
      : {};

  useEffect(() => {
    const interval = window.setInterval(() => {
      setFrameCursor(prev => (prev + 1) % 4);
    }, IDLE_FRAME_MS);

    return () => window.clearInterval(interval);
  }, []);

  return (
    <div
      className={className}
      style={{
        position: 'relative',
        width: `${TILE_SIZE * 2.6}px`,
        height: `${TILE_SIZE * 3.1}px`,
        transform: `translateY(${bobY}px) scale(${scale})`,
        transformOrigin: 'bottom center',
      }}
    >
      <div
        style={{
          position: 'absolute',
          inset: 0,
          transform: facing === 'left' ? 'scaleX(-1)' : undefined,
          transformOrigin: 'bottom center',
        }}
      >
        <div style={{ position: 'absolute', left: '50%', bottom: 0, width: `${TILE_SIZE}px`, height: `${TILE_SIZE}px`, transform: 'translateX(-50%)' }}>
          <div className={getPartClassName('body')} style={{ position: 'absolute', left: `${layout.body.x}px`, top: `${layout.body.y}px` }} {...getPartHandlers('body')}>
            <LayerSprite src={visual.bodySrc} frameIndex={bodyFrame} zIndex={1} />
          </div>

          <div
            className={getPartClassName('hand')}
            style={{ position: 'absolute', left: `${layout.hand.x}px`, top: `${layout.hand.y}px`, width: `${HAND_TILE_SIZE}px`, height: `${HAND_TILE_SIZE}px`, zIndex: 5 }}
            {...getPartHandlers('hand')}
          >
            {visual.mainHand && (
              <div className={getPartClassName('mainHand')} style={{ position: 'absolute', left: `${layout.mainHand.x}px`, top: `${layout.mainHand.y}px` }} {...getPartHandlers('mainHand')}>
                <AtlasSprite spec={visual.mainHand} zIndex={11} />
              </div>
            )}
            <LayerSprite src={visual.handSrc} frameIndex={handFrame} tileSize={HAND_TILE_SIZE} zIndex={12} />
          </div>

          <div className={getPartClassName('head')} style={{ position: 'absolute', left: `${layout.head.x}px`, top: `${layout.head.y}px` }} {...getPartHandlers('head')}>
            <LayerSprite src={visual.headSrc} frameIndex={headFrame} zIndex={6} />
          </div>
          {visual.facialHairSrc && (
            <div className={getPartClassName('facialHair')} style={{ position: 'absolute', left: `${layout.facialHair.x}px`, top: `${layout.facialHair.y}px` }} {...getPartHandlers('facialHair')}>
              <LayerSprite src={visual.facialHairSrc} frameIndex={facialFrame} zIndex={7} />
            </div>
          )}
          <div className={getPartClassName('hair')} style={{ position: 'absolute', left: `${layout.hair.x}px`, top: `${layout.hair.y}px` }} {...getPartHandlers('hair')}>
            <LayerSprite src={visual.hairSrc} frameIndex={hairFrame} zIndex={8} />
          </div>
          {visual.headgear && (
            <div className={getPartClassName('headgear')} style={{ position: 'absolute', left: `${layout.headgear.x}px`, top: `${layout.headgear.y}px` }} {...getPartHandlers('headgear')}>
              <AtlasSprite spec={visual.headgear} zIndex={9} />
            </div>
          )}
          {visual.offHand && (
            <div className={getPartClassName('offHand')} style={{ position: 'absolute', left: `${layout.offHand.x}px`, top: `${layout.offHand.y}px` }} {...getPartHandlers('offHand')}>
              <AtlasSprite spec={visual.offHand} zIndex={10} />
            </div>
          )}
          </div>
      </div>
    </div>
  );
}
