import type { CombatLockState, Vec3 } from "../shared/types";
import type { ImpactView, ProjectileView } from "../shared/Projectiles";

export type CombatModule = {
  id: string;
  key: string;
  name: string;
  type: string;
  cooldown: number;
  maxCooldown: number;
  cost: number;
  damage: number;
  color: string;
};

export type CombatState = {
  player: { shields: number; armor: number; hull: number; energy: number; maxEnergy: number; speed: number };
  enemy: { shields: number; armor: number; hull: number; weapons: number; engines: number };
  power: { weapons: number; shields: number; engines: number; aux: number };
  lockState: CombatLockState;
  lockProgress: number;
  subsystem: "shields" | "hull" | "weapons" | "engines";
  modules: CombatModule[];
  projectiles: Array<ProjectileView & { owner: "player" | "enemy"; damage: number; subsystem: CombatState["subsystem"] | "hull" }>;
  impacts: ImpactView[];
  log: Array<{ time: string; msg: string; color: string }>;
  overloadedUntil: number;
  afterburnUntil: number;
  playerFireClock: number;
  enemyFireClock: number;
};

type TickPayload = {
  dt: number;
  playerPosition: Vec3;
  enemyPosition: Vec3;
  elapsed: number;
};

export type CombatAction =
  | { type: "startLock" }
  | { type: "adjustPower"; system: keyof CombatState["power"]; delta: number }
  | { type: "setSubsystem"; subsystem: CombatState["subsystem"] }
  | { type: "castModule"; id: string; playerPosition: Vec3; enemyPosition: Vec3; elapsed: number }
  | { type: "tick"; payload: TickPayload };

const nowStamp = () => new Date().toLocaleTimeString("en", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });

function addLog(state: CombatState, msg: string, color = "#94a3b8"): CombatState {
  return { ...state, log: [...state.log.slice(-50), { time: nowStamp(), msg, color }] };
}

const clamp100 = (value: number) => Math.max(0, Math.min(100, value));
const uid = () => Math.random().toString(36).slice(2);

export const initialCombatState: CombatState = {
  player: { shields: 100, armor: 100, hull: 100, energy: 100, maxEnergy: 100, speed: 0 },
  enemy: { shields: 100, armor: 100, hull: 100, weapons: 100, engines: 100 },
  power: { weapons: 3, shields: 2, engines: 2, aux: 1 },
  lockState: "idle",
  lockProgress: 0,
  subsystem: "hull",
  modules: [
    { id: "q", key: "1", name: "Railgun", type: "weapon", cooldown: 0, maxCooldown: 3, cost: 12, damage: 18, color: "#ef4444" },
    { id: "w", key: "2", name: "Shield Bst", type: "shield", cooldown: 0, maxCooldown: 8, cost: 20, damage: 0, color: "#22d3ee" },
    { id: "e", key: "3", name: "EM Pulse", type: "ewar", cooldown: 0, maxCooldown: 12, cost: 30, damage: 0, color: "#a78bfa" },
    { id: "r", key: "4", name: "Overload", type: "reactor", cooldown: 0, maxCooldown: 30, cost: 45, damage: 0, color: "#f0a030" },
    { id: "d", key: "5", name: "Afterburn", type: "engine", cooldown: 0, maxCooldown: 6, cost: 10, damage: 0, color: "#22c55e" },
    { id: "f", key: "6", name: "Hull Patch", type: "repair", cooldown: 0, maxCooldown: 15, cost: 25, damage: 0, color: "#fb923c" },
  ],
  projectiles: [],
  impacts: [],
  log: [{ time: nowStamp(), msg: "Combat systems online.", color: "#22d3ee" }],
  overloadedUntil: 0,
  afterburnUntil: 0,
  playerFireClock: 0,
  enemyFireClock: 0,
};

function damageEnemy(state: CombatState, damage: number, subsystem: CombatState["subsystem"]) {
  const enemy = { ...state.enemy };
  if (subsystem === "shields") enemy.shields = clamp100(enemy.shields - damage);
  if (subsystem === "weapons") enemy.weapons = clamp100(enemy.weapons - damage);
  if (subsystem === "engines") enemy.engines = clamp100(enemy.engines - damage);
  if (subsystem === "hull") {
    if (enemy.shields > 0) enemy.shields = clamp100(enemy.shields - damage * 0.5);
    else if (enemy.armor > 0) enemy.armor = clamp100(enemy.armor - damage * 0.55);
    else enemy.hull = clamp100(enemy.hull - damage);
  }
  return enemy;
}

export function combatReducer(state: CombatState, action: CombatAction): CombatState {
  if (action.type === "startLock") {
    return addLog({ ...state, lockState: "locking", lockProgress: 0 }, "Initiating target lock...", "#f0a030");
  }

  if (action.type === "adjustPower") {
    const next = Math.max(0, state.power[action.system] + action.delta);
    const total = Object.entries(state.power).reduce((sum, [key, value]) => sum + (key === action.system ? next : value), 0);
    if (total > 8) return state;
    return { ...state, power: { ...state.power, [action.system]: next } };
  }

  if (action.type === "setSubsystem") return { ...state, subsystem: action.subsystem };

  if (action.type === "castModule") {
    const module = state.modules.find((item) => item.id === action.id);
    if (!module) return state;
    if (state.lockState !== "locked") return addLog(state, "Target not locked yet.", "#ef4444");
    if (module.cooldown > 0) return addLog(state, `${module.name} recharging.`, "#ef4444");
    if (state.player.energy < module.cost) return addLog(state, "Insufficient energy.", "#ef4444");

    const auxReduction = Math.min(0.6, state.power.aux * 0.06);
    let next: CombatState = {
      ...state,
      player: { ...state.player, energy: state.player.energy - module.cost },
      modules: state.modules.map((item) => item.id === module.id ? { ...item, cooldown: Math.max(0.5, module.maxCooldown * (1 - auxReduction)) } : item),
    };

    if (module.id === "q") {
      next = {
        ...next,
        projectiles: [...next.projectiles, {
          id: uid(), from: action.playerPosition, to: action.enemyPosition, progress: 0, color: module.color,
          owner: "player", damage: module.damage * (1 + state.power.weapons * 0.2), subsystem: state.subsystem,
        }],
      };
      return addLog(next, `Railgun -> ${state.subsystem.toUpperCase()}`, module.color);
    }
    if (module.id === "w") {
      return addLog({ ...next, player: { ...next.player, shields: clamp100(next.player.shields + 18 + state.power.shields * 5) } }, "Shield boost cycled.", module.color);
    }
    if (module.id === "e") {
      return addLog({
        ...next,
        enemy: { ...next.enemy, weapons: clamp100(next.enemy.weapons - 18 - state.power.aux * 3), engines: clamp100(next.enemy.engines - 14 - state.power.aux * 3) },
        impacts: [...next.impacts, { id: uid(), position: action.enemyPosition, color: module.color, age: 0 }],
      }, "EM pulse disrupted enemy weapons and engines.", module.color);
    }
    if (module.id === "r") return addLog({ ...next, overloadedUntil: action.elapsed + 8 }, "OVERLOAD: fire rate increased.", module.color);
    if (module.id === "d") return addLog({ ...next, afterburnUntil: action.elapsed + 3 }, "Afterburners engaged.", module.color);
    if (module.id === "f") return addLog({ ...next, player: { ...next.player, hull: clamp100(next.player.hull + 14 + state.power.aux * 4) } }, "Hull patch applied.", module.color);
    return next;
  }

  if (action.type === "tick") {
    const { dt, playerPosition, enemyPosition, elapsed } = action.payload;
    const overloaded = elapsed < state.overloadedUntil;
    const locked = state.lockState === "locked";
    let next: CombatState = {
      ...state,
      player: {
        ...state.player,
        energy: clamp100(state.player.energy + dt * (2 + state.power.aux * 2) - (overloaded ? dt * 3 : 0)),
        shields: clamp100(state.player.shields + dt * state.power.shields * 1.2),
      },
      modules: state.modules.map((module) => ({ ...module, cooldown: Math.max(0, module.cooldown - dt) })),
      projectiles: state.projectiles.map((projectile) => ({ ...projectile, progress: projectile.progress + dt * 1.8 })),
      impacts: state.impacts.map((impact) => ({ ...impact, age: impact.age + dt * 8 })).filter((impact) => impact.age < 7),
    };

    if (state.lockState === "locking") {
      const progress = Math.min(1, state.lockProgress + dt / 3);
      next = { ...next, lockProgress: progress, lockState: progress >= 1 ? "locked" : "locking" };
      if (progress >= 1 && state.lockProgress < 1) next = addLog(next, "TARGET LOCKED", "#22c55e");
    }

    if (locked && state.enemy.hull > 0) {
      const playerInterval = Math.max(0.22, (overloaded ? 0.55 : 1.1) - state.power.weapons * 0.08);
      const enemyInterval = Math.max(0.45, 1.35 + (100 - state.enemy.weapons) * 0.02);
      next.playerFireClock += dt;
      next.enemyFireClock += dt;
      if (next.playerFireClock >= playerInterval) {
        next.playerFireClock = 0;
        next.projectiles.push({
          id: uid(),
          from: playerPosition,
          to: enemyPosition,
          progress: 0,
          color: overloaded ? "#fbbf24" : "#f0a030",
          owner: "player",
          damage: 4 + state.power.weapons * 1.8,
          subsystem: state.subsystem,
        });
      }
      if (next.enemyFireClock >= enemyInterval && state.enemy.weapons > 10) {
        next.enemyFireClock = 0;
        next.projectiles.push({
          id: uid(),
          from: enemyPosition,
          to: playerPosition,
          progress: 0,
          color: "#ef4444",
          owner: "enemy",
          damage: 4 * (state.enemy.weapons / 100),
          subsystem: "hull",
        });
      }
    }

    const activeProjectiles = [];
    for (const projectile of next.projectiles) {
      if (projectile.progress < 1) {
        activeProjectiles.push(projectile);
        continue;
      }
      next.impacts.push({ id: uid(), position: projectile.to, color: projectile.color, age: 0 });
      if (projectile.owner === "player") {
        next.enemy = damageEnemy(next, projectile.damage, projectile.subsystem as CombatState["subsystem"]);
      } else {
        const absorbed = Math.min(next.player.shields, projectile.damage * (0.5 + state.power.shields * 0.08));
        const bleed = projectile.damage - absorbed;
        next.player = {
          ...next.player,
          shields: clamp100(next.player.shields - absorbed),
          armor: clamp100(next.player.armor - Math.max(0, bleed * 0.6)),
          hull: clamp100(next.player.hull - Math.max(0, bleed * 0.2)),
        };
      }
    }
    next.projectiles = activeProjectiles;
    return next;
  }

  return state;
}
