import { ArrowLeft, Loader2 } from 'lucide-react';
import { useEffect, useRef, useState, type PointerEvent } from 'react';

import type {
  BigFishAssetSlotResponse,
  BigFishRuntimeEntityResponse,
  BigFishRuntimeSnapshotResponse,
  SubmitBigFishInputRequest,
} from '../../../packages/shared/src/contracts/bigFish';
import { ResolvedAssetImage } from '../ResolvedAssetImage';

type TouchOrigin = {
  pointerId: number;
  x: number;
  y: number;
};

type BigFishRuntimeShellProps = {
  run: BigFishRuntimeSnapshotResponse | null;
  assetSlots?: BigFishAssetSlotResponse[];
  isBusy?: boolean;
  error?: string | null;
  onBack: () => void;
  onSubmitInput: (payload: SubmitBigFishInputRequest) => void;
};

function clamp(value: number, min: number, max: number) {
  return Math.max(min, Math.min(max, value));
}

function normalizeVector(x: number, y: number) {
  const length = Math.hypot(x, y);
  if (length <= 0.001) {
    return { x: 0, y: 0 };
  }
  const capped = Math.min(1, length);
  return {
    x: (x / length) * capped,
    y: (y / length) * capped,
  };
}

function resolveDirectionFromOrigin(
  origin: TouchOrigin,
  clientX: number,
  clientY: number,
) {
  const deadZone = 12;
  const deltaX = clientX - origin.x;
  const deltaY = clientY - origin.y;
  if (Math.hypot(deltaX, deltaY) < deadZone) {
    return { x: 0, y: 0 };
  }
  return normalizeVector(deltaX, deltaY);
}

function projectEntity(
  entity: BigFishRuntimeEntityResponse,
  run: BigFishRuntimeSnapshotResponse,
) {
  const viewportWidth = 360;
  const viewportHeight = 640;
  const worldWidth = 420;
  const worldHeight = 760;
  const x =
    viewportWidth / 2 +
    ((entity.position.x - run.cameraCenter.x) / worldWidth) * viewportWidth;
  const y =
    viewportHeight / 2 +
    ((entity.position.y - run.cameraCenter.y) / worldHeight) * viewportHeight;

  return {
    left: `${clamp(x, -40, viewportWidth + 40)}px`,
    top: `${clamp(y, -40, viewportHeight + 40)}px`,
    width: `${Math.max(22, entity.radius * 2.2)}px`,
    height: `${Math.max(22, entity.radius * 2.2)}px`,
  };
}

function findBigFishAssetSlot(
  slots: BigFishAssetSlotResponse[],
  assetKind: string,
  level?: number,
  motionKey?: string,
) {
  return slots.find((slot) => {
    if (slot.assetKind !== assetKind || slot.status !== 'ready') {
      return false;
    }
    if (level !== undefined && slot.level !== level) {
      return false;
    }
    if (motionKey !== undefined && slot.motionKey !== motionKey) {
      return false;
    }
    return true;
  });
}

function resolveRuntimeEntityAsset(
  entity: BigFishRuntimeEntityResponse,
  assetSlots: BigFishAssetSlotResponse[],
) {
  return (
    findBigFishAssetSlot(assetSlots, 'level_motion', entity.level, 'move_swim') ??
    findBigFishAssetSlot(assetSlots, 'level_motion', entity.level, 'idle_float') ??
    findBigFishAssetSlot(assetSlots, 'level_main_image', entity.level)
  );
}

function resolveSettlementCopy(run: BigFishRuntimeSnapshotResponse) {
  if (run.status === 'won') {
    return {
      title: '通关完成',
      message: `已成长到 Lv.${run.playerLevel}，本轮生态征服完成。`,
      tone: 'from-emerald-300/28 via-cyan-300/18 to-white/10',
    };
  }
  if (run.status === 'failed') {
    return {
      title: '本轮失败',
      message: '己方鱼群已经耗尽，重新调整路线再来一次。',
      tone: 'from-rose-300/30 via-orange-300/16 to-white/10',
    };
  }
  return null;
}

function BigFishEntityDot({
  entity,
  run,
  owned,
  assetSlots,
}: {
  entity: BigFishRuntimeEntityResponse;
  run: BigFishRuntimeSnapshotResponse;
  owned: boolean;
  assetSlots: BigFishAssetSlotResponse[];
}) {
  const projected = projectEntity(entity, run);
  const isLeader = run.leaderEntityId === entity.entityId;
  const assetSlot = resolveRuntimeEntityAsset(entity, assetSlots);
  const entityImageSrc = assetSlot?.assetUrl?.trim() || null;

  return (
    <div
      className={`absolute -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-full border shadow-lg transition-all ${
        entityImageSrc
          ? owned
            ? isLeader
              ? 'border-cyan-50 shadow-cyan-950/40'
              : 'border-cyan-100/80 shadow-cyan-950/28'
            : entity.level > run.playerLevel
              ? 'border-rose-100/80 shadow-rose-950/28'
              : 'border-emerald-100/80 shadow-emerald-950/24'
          : owned
            ? isLeader
              ? 'border-cyan-100 bg-cyan-300 shadow-cyan-950/30'
              : 'border-cyan-100/70 bg-cyan-500/88 shadow-cyan-950/24'
            : entity.level > run.playerLevel
              ? 'border-rose-100/70 bg-rose-500/88 shadow-rose-950/24'
              : 'border-emerald-100/70 bg-emerald-400/88 shadow-emerald-950/20'
      }`}
      style={projected}
    >
      {entityImageSrc ? (
        <>
          <ResolvedAssetImage
            src={entityImageSrc}
            alt={`Lv.${entity.level} 实体`}
            className={`h-full w-full object-cover ${
              owned && isLeader ? 'scale-110' : ''
            }`}
          />
          <div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,transparent_32%,rgba(2,6,23,0.18)_72%,rgba(2,6,23,0.36)_100%)]" />
        </>
      ) : null}
      <span className="absolute inset-0 flex items-center justify-center text-[0.62rem] font-black text-white [text-shadow:0_1px_2px_rgba(2,6,23,0.9)]">
        {entity.level}
      </span>
    </div>
  );
}

export function BigFishRuntimeShell({
  run,
  assetSlots = [],
  isBusy = false,
  error = null,
  onBack,
  onSubmitInput,
}: BigFishRuntimeShellProps) {
  const stageRef = useRef<HTMLDivElement | null>(null);
  const [touchOrigin, setTouchOrigin] = useState<TouchOrigin | null>(null);
  const [stick, setStick] = useState({ x: 0, y: 0 });
  const stickRef = useRef(stick);

  useEffect(() => {
    stickRef.current = stick;
  }, [stick]);

  useEffect(() => {
    const timer = window.setInterval(() => {
      const current = stickRef.current;
      // 即使没有方向输入也持续回传当前状态，让后端持续推进刷怪、清理与胜负裁决。
      onSubmitInput(current);
    }, 220);

    return () => {
      window.clearInterval(timer);
    };
  }, [onSubmitInput]);

  const submitDirection = (direction: SubmitBigFishInputRequest) => {
    setStick(direction);
    onSubmitInput(direction);
  };

  const beginTouchControl = (event: PointerEvent<HTMLDivElement>) => {
    if (event.target instanceof HTMLElement && event.target.closest('button')) {
      return;
    }
    event.currentTarget.setPointerCapture(event.pointerId);
    setTouchOrigin({
      pointerId: event.pointerId,
      x: event.clientX,
      y: event.clientY,
    });
    submitDirection({ x: 0, y: 0 });
  };

  const updateTouchControl = (event: PointerEvent<HTMLDivElement>) => {
    if (!touchOrigin || touchOrigin.pointerId !== event.pointerId) {
      return;
    }
    submitDirection(
      resolveDirectionFromOrigin(touchOrigin, event.clientX, event.clientY),
    );
  };

  const endTouchControl = (event: PointerEvent<HTMLDivElement>) => {
    if (!touchOrigin || touchOrigin.pointerId !== event.pointerId) {
      return;
    }
    setTouchOrigin(null);
    submitDirection({ x: 0, y: 0 });
  };

  if (!run) {
    return (
      <div className="fixed inset-0 z-[100] flex items-center justify-center bg-slate-950 text-white">
        <div className="flex items-center gap-2 rounded-full bg-white/10 px-5 py-3 text-sm">
          <Loader2 className="h-4 w-4 animate-spin" />
          正在进入玩法
        </div>
      </div>
    );
  }

  const statusLabel =
    run.status === 'won' ? '通关' : run.status === 'failed' ? '失败' : '进行中';
  const settlementCopy = resolveSettlementCopy(run);
  const backgroundAsset =
    findBigFishAssetSlot(assetSlots, 'stage_background')?.assetUrl?.trim() || null;

  return (
    <div className="fixed inset-0 z-[100] flex justify-center bg-slate-950 text-white">
      <div
        ref={stageRef}
        className="relative h-full w-full max-w-[430px] touch-none overflow-hidden bg-[radial-gradient(circle_at_50%_20%,rgba(34,211,238,0.2),transparent_28%),radial-gradient(circle_at_20%_80%,rgba(16,185,129,0.18),transparent_26%),linear-gradient(180deg,#082f49,#020617)]"
        onPointerDown={beginTouchControl}
        onPointerMove={updateTouchControl}
        onPointerUp={endTouchControl}
        onPointerCancel={endTouchControl}
      >
        {backgroundAsset ? (
          <ResolvedAssetImage
            src={backgroundAsset}
            alt="大鱼吃小鱼场地背景"
            className="absolute inset-0 h-full w-full object-cover"
          />
        ) : null}
        <div className="pointer-events-none absolute inset-0 bg-[linear-gradient(180deg,rgba(8,47,73,0.2),rgba(2,6,23,0.6))]" />
        <div className="pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.04)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.04)_1px,transparent_1px)] bg-[length:32px_32px] opacity-30" />

        <div className="absolute left-0 top-0 z-20 flex w-full items-center justify-between px-4 py-4">
          <button
            type="button"
            onClick={onBack}
            className="pointer-events-auto inline-flex h-10 w-10 items-center justify-center rounded-full bg-black/28 backdrop-blur"
          >
            <ArrowLeft className="h-4 w-4" />
          </button>
          <div className="rounded-full bg-black/28 px-4 py-2 text-xs font-bold backdrop-blur">
            Lv.{run.playerLevel}/{run.winLevel} · {statusLabel}
          </div>
        </div>

        <div className="absolute left-1/2 top-1/2 h-[640px] w-[360px] -translate-x-1/2 -translate-y-1/2">
          {run.wildEntities.map((entity) => (
            <BigFishEntityDot
              key={entity.entityId}
              entity={entity}
              run={run}
              owned={false}
              assetSlots={assetSlots}
            />
          ))}
          {run.ownedEntities.map((entity) => (
            <BigFishEntityDot
              key={entity.entityId}
              entity={entity}
              run={run}
              owned
              assetSlots={assetSlots}
            />
          ))}
        </div>

        {settlementCopy ? (
          <div className="pointer-events-none absolute inset-0 z-40 flex items-center justify-center px-5">
            <div
              className={`w-full max-w-[20rem] rounded-[2rem] border border-white/24 bg-gradient-to-br ${settlementCopy.tone} p-6 text-center shadow-2xl shadow-slate-950/45 backdrop-blur-xl`}
            >
              <div className="text-3xl font-black tracking-[0.22em] text-white [text-shadow:0_2px_12px_rgba(2,6,23,0.6)]">
                {settlementCopy.title}
              </div>
              <div className="mt-3 text-sm font-semibold leading-6 text-white/82">
                {settlementCopy.message}
              </div>
            </div>
          </div>
        ) : null}

        <div className="pointer-events-none absolute bottom-6 right-4 z-30 max-w-[13rem] space-y-2 text-right text-xs text-white/72">
          {isBusy ? <div>同步中...</div> : null}
          {error ? <div className="text-rose-200">{error}</div> : null}
          {run.eventLog.slice(-3).map((event) => (
            <div key={event} className="rounded-full bg-black/22 px-3 py-1">
              {event}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

export default BigFishRuntimeShell;
