﻿import { useCallback, useMemo, useState } from 'react';

import type {
  BigFishAssetSlotResponse,
  BigFishRuntimeEntityResponse,
  BigFishRuntimeSnapshotResponse,
  SubmitBigFishInputRequest,
} from '../packages/shared/src/contracts/bigFish';
import { BigFishRuntimeShell } from './components/big-fish-runtime/BigFishRuntimeShell';

const BIG_FISH_BACKGROUND_IMAGE =
  'data:image/svg+xml;utf8,' +
  encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 1280">
  <defs>
    <linearGradient id="water" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#38bdf8" />
      <stop offset="0.52" stop-color="#0f766e" />
      <stop offset="1" stop-color="#020617" />
    </linearGradient>
    <radialGradient id="light" cx="50%" cy="12%" r="52%">
      <stop offset="0" stop-color="#ecfeff" stop-opacity="0.72" />
      <stop offset="1" stop-color="#ecfeff" stop-opacity="0" />
    </radialGradient>
  </defs>
  <rect width="720" height="1280" fill="url(#water)" />
  <rect width="720" height="1280" fill="url(#light)" />
  <path d="M70 324 C164 268 256 384 362 320 C492 242 582 330 656 282" fill="none" stroke="#a7f3d0" stroke-width="16" stroke-linecap="round" opacity="0.28" />
  <path d="M34 760 C156 700 238 806 372 724 C520 634 606 746 704 682" fill="none" stroke="#bae6fd" stroke-width="18" stroke-linecap="round" opacity="0.18" />
  <circle cx="120" cy="210" r="18" fill="#ecfeff" opacity="0.36" />
  <circle cx="548" cy="410" r="12" fill="#ecfeff" opacity="0.28" />
  <circle cx="304" cy="590" r="10" fill="#ecfeff" opacity="0.24" />
  <path d="M0 1060 C128 1010 244 1096 366 1030 C492 962 612 1026 720 976 V1280 H0 Z" fill="#022c22" opacity="0.62" />
</svg>`);

const WORLD_MIN_X = 60;
const WORLD_MAX_X = 780;
const WORLD_MIN_Y = 80;
const WORLD_MAX_Y = 1240;
const PLAYER_SPEED = 20;

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

function buildEntity(
  entityId: string,
  level: number,
  x: number,
  y: number,
): BigFishRuntimeEntityResponse {
  return {
    entityId,
    level,
    position: { x, y },
    radius: 12 + level * 5,
    offscreenSeconds: 0,
  };
}

function buildInitialRun(): BigFishRuntimeSnapshotResponse {
  const leader = buildEntity('player-leader', 1, 360, 640);
  return {
    runId: `local-big-fish-run-${Date.now()}`,
    sessionId: 'local-big-fish-session',
    status: 'running',
    tick: 0,
    playerLevel: 1,
    winLevel: 5,
    leaderEntityId: leader.entityId,
    ownedEntities: [leader],
    wildEntities: [
      buildEntity('wild-small-1', 1, 250, 560),
      buildEntity('wild-small-2', 1, 470, 760),
      buildEntity('wild-mid-1', 2, 560, 520),
      buildEntity('wild-mid-2', 3, 210, 820),
      buildEntity('wild-boss-1', 5, 610, 930),
    ],
    cameraCenter: { ...leader.position },
    lastInput: { x: 0, y: 0 },
    eventLog: ['按住屏幕任意位置，再拖动控制方向。'],
    updatedAt: new Date().toISOString(),
  };
}

function distanceBetween(
  first: BigFishRuntimeEntityResponse,
  second: BigFishRuntimeEntityResponse,
) {
  return Math.hypot(
    first.position.x - second.position.x,
    first.position.y - second.position.y,
  );
}

function respawnWildEntity(entity: BigFishRuntimeEntityResponse, tick: number) {
  const offset = tick * 37 + entity.level * 53;
  return {
    ...entity,
    position: {
      x: WORLD_MIN_X + (offset % Math.floor(WORLD_MAX_X - WORLD_MIN_X)),
      y: WORLD_MIN_Y + ((offset * 7) % Math.floor(WORLD_MAX_Y - WORLD_MIN_Y)),
    },
  };
}

function moveWildEntity(entity: BigFishRuntimeEntityResponse, tick: number) {
  const phase = tick * 0.32 + entity.level * 1.7;
  const speed = 6 + entity.level * 0.8;
  const nextX = entity.position.x + Math.cos(phase) * speed;
  const nextY = entity.position.y + Math.sin(phase * 0.73) * speed;
  return {
    ...entity,
    position: {
      x: clamp(nextX, WORLD_MIN_X, WORLD_MAX_X),
      y: clamp(nextY, WORLD_MIN_Y, WORLD_MAX_Y),
    },
  };
}

function applyLocalInput(
  run: BigFishRuntimeSnapshotResponse,
  input: SubmitBigFishInputRequest,
): BigFishRuntimeSnapshotResponse {
  if (run.status !== 'running') {
    return run;
  }

  const leader = run.ownedEntities.find(
    (entity) => entity.entityId === run.leaderEntityId,
  );
  if (!leader) {
    return run;
  }

  const nextLeader = {
    ...leader,
    position: {
      x: clamp(leader.position.x + input.x * PLAYER_SPEED, WORLD_MIN_X, WORLD_MAX_X),
      y: clamp(leader.position.y + input.y * PLAYER_SPEED, WORLD_MIN_Y, WORLD_MAX_Y),
    },
  };

  let nextPlayerLevel = run.playerLevel;
  const nextEvents = [...run.eventLog];
  const nextWildEntities = run.wildEntities.map((entity) => {
    const movedEntity = moveWildEntity(entity, run.tick + 1);
    const touched = distanceBetween(nextLeader, movedEntity) <= nextLeader.radius + movedEntity.radius;
    if (!touched) {
      return movedEntity;
    }

    if (movedEntity.level <= nextPlayerLevel) {
      nextPlayerLevel = Math.min(run.winLevel, nextPlayerLevel + 1);
      nextEvents.push(`吞噬 Lv.${movedEntity.level}，成长到 Lv.${nextPlayerLevel}`);
      return respawnWildEntity(movedEntity, run.tick + nextPlayerLevel);
    }

    nextEvents.push(`撞上 Lv.${movedEntity.level}，暂时避开更大的鱼。`);
    return movedEntity;
  });

  const scaledLeader = {
    ...nextLeader,
    level: nextPlayerLevel,
    radius: 12 + nextPlayerLevel * 5,
  };
  const status = nextPlayerLevel >= run.winLevel ? 'won' : 'running';
  if (status === 'won' && run.status !== 'won') {
    nextEvents.push('已经成长为海域霸主。');
  }

  return {
    ...run,
    status,
    tick: run.tick + 1,
    playerLevel: nextPlayerLevel,
    ownedEntities: [scaledLeader],
    wildEntities: nextWildEntities,
    cameraCenter: { ...scaledLeader.position },
    lastInput: input,
    eventLog: nextEvents.slice(-5),
    updatedAt: new Date().toISOString(),
  };
}

export default function BigFishPlaygroundApp() {
  const [run, setRun] = useState(buildInitialRun);
  const assetSlots = useMemo<BigFishAssetSlotResponse[]>(
    () => [
      {
        slotId: 'local-big-fish-background',
        assetKind: 'stage_background',
        status: 'ready',
        assetUrl: BIG_FISH_BACKGROUND_IMAGE,
        promptSnapshot: '本地直达入口占位海域背景',
        updatedAt: new Date(0).toISOString(),
      },
    ],
    [],
  );

  const handleSubmitInput = useCallback((payload: SubmitBigFishInputRequest) => {
    setRun((currentRun) => applyLocalInput(currentRun, payload));
  }, []);

  const handleRestart = useCallback(() => {
    setRun(buildInitialRun());
  }, []);

  const handleExit = useCallback(() => {
    window.location.assign('/');
  }, []);

  return (
    <BigFishRuntimeShell
      run={run}
      assetSlots={assetSlots}
      onBack={handleExit}
      onRestart={handleRestart}
      onSubmitInput={handleSubmitInput}
    />
  );
}
