// ─── Combat Descent Actions ────────────────────────────────────────────────────
// Extracted from combatStore.ts to keep the store under the 400-line limit.
// Implements the spec-driven descent system (climbing spec §4.4–§4.9).

import type { CombatState, CombatStore } from './combat-state.types';
import { generateSpireFloorState, getRoomsForFloor } from '../utils/spire-utils';
import { getGuardianForFloor } from '../data/guardian-encounters';
import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { summonGolemsOnRoomEntry } from './golem-combat-actions';
import { computeDisciplineEffects } from '../effects/discipline-effects';
import { useAttunementStore } from './attunementStore';
import { useDisciplineStore } from './discipline-slice';
import {
  onEnterLibraryRoom,
  onEnterRecoveryRoom,
  onEnterTreasureRoom,
  onEnterPuzzleRoom,
} from './non-combat-room-actions';


type GetFn = () => CombatStore;
type SetFn = (state: Partial<CombatState>) => void;

/** Helper: compute total enemy HP from a room */
function calcRoomHP(room: { enemies?: Array<{ hp: number }> }): number {
  if (!room.enemies || room.enemies.length === 0) return 0;
  return room.enemies.reduce((sum, e) => sum + e.hp, 0);
}

/**
 * Compute coverage carryover for the resonant-stamps perk.
 * Returns min(20, currentCoverage * 0.2) if the perk is unlocked, else 0.
 */
function computeCoverageCarryover(currentCoverage: number): number {
  const discEffects = computeDisciplineEffects();
  if (!discEffects.specials.has('resonant-stamps')) return 0;
  return Math.min(20, currentCoverage * 0.2);
}

// ─── enterDescentMode (climbing spec §4.5) ────────────────────────────────────

export function enterDescentMode(get: GetFn, set: SetFn): void {
  const s = get();
  set({
    climbDirection: 'down',
    descentPeak: { floor: s.currentFloor, roomIndex: s.currentRoomIndex },
    isDescentComplete: false,
    runId: s.runId,
  });
  get().addActivityLog('floor_transition',
    `Beginning descent from Floor ${s.currentFloor}, Room ${s.currentRoomIndex + 1}`);
  onEnterRoomDescend(get, set);
}

// ─── advanceRoomOrFloor (climbing spec §4.4, §4.6) ────────────────────────────

export function advanceRoomOrFloor(get: GetFn, set: SetFn): void {
  const s = get();

  if (s.climbDirection === 'down') {
    get().addActivityLog('floor_transition', `Room ${s.currentRoomIndex + 1} passed`);

    if (s.currentFloor <= s.exitFloor && s.currentRoomIndex <= 0) {
      set({ isDescentComplete: true, castProgress: 0, weaponCastProgress: {} });
      get().addActivityLog('floor_transition',
        'Descent complete — Exit Spire is now available');
      return;
    }

    const carryover = computeCoverageCarryover(s.currentRoom.roomEnchantment?.coverage ?? 0);
    get().setLastRoomCoverage(carryover);

    if (s.currentRoomIndex <= 0) {
      const newFloor = s.currentFloor - 1;
      const seed = newFloor * 12345 + s.runId;
      const newRoomsPerFloor = getRoomsForFloor(newFloor, seed);
      const newRoomIndex = newRoomsPerFloor - 1;
      const newRoom = generateSpireFloorState(newFloor, newRoomIndex, newRoomsPerFloor, s.runId);
      const newFloorHP = calcRoomHP(newRoom);
      set({
        currentFloor: newFloor,
        currentRoomIndex: newRoomIndex,
        roomsPerFloor: newRoomsPerFloor,
        currentRoom: newRoom,
        floorHP: newFloorHP,
        floorMaxHP: newFloorHP,
        castProgress: 0,
        weaponCastProgress: {},
      });
      get().addActivityLog('floor_transition', `Descended to Floor ${newFloor}`);
    } else {
      const newRoomIndex = s.currentRoomIndex - 1;
      const newRoom = generateSpireFloorState(s.currentFloor, newRoomIndex, s.roomsPerFloor, s.runId);
      const newFloorHP = calcRoomHP(newRoom);
      set({
        currentRoomIndex: newRoomIndex,
        currentRoom: newRoom,
        floorHP: newFloorHP,
        floorMaxHP: newFloorHP,
        castProgress: 0,
        weaponCastProgress: {},
      });
    }

    summonGolemsForRoom(get, set);
    onEnterRoomDescend(get, set);
  } else {
    const roomKey = `${s.currentFloor}:${s.currentRoomIndex}`;
    set((prev) => ({
      clearedRooms: { ...prev.clearedRooms, [roomKey]: true },
    }));
    get().addActivityLog('floor_transition',
      `Floor ${s.currentFloor} Room ${s.currentRoomIndex + 1}/${s.roomsPerFloor} cleared`);

    const carryover = computeCoverageCarryover(s.currentRoom.roomEnchantment?.coverage ?? 0);
    get().setLastRoomCoverage(carryover);

    if (s.currentRoomIndex + 1 >= s.roomsPerFloor) {
      const newFloor = Math.min(s.currentFloor + 1, 100);
      const newRoomsPerFloor = getRoomsForFloor(newFloor, newFloor * 12345 + s.runId);
      const newRoom = generateSpireFloorState(newFloor, 0, newRoomsPerFloor, s.runId);
      const newFloorHP = calcRoomHP(newRoom);
      set({
        currentFloor: newFloor,
        currentRoomIndex: 0,
        roomsPerFloor: newRoomsPerFloor,
        currentRoom: newRoom,
        floorHP: newFloorHP,
        floorMaxHP: newFloorHP,
        castProgress: 0,
        weaponCastProgress: {},
      });
      get().addActivityLog('floor_transition', `Ascending to Floor ${newFloor}`);
    } else {
      const newRoomIndex = s.currentRoomIndex + 1;
      const newRoom = generateSpireFloorState(s.currentFloor, newRoomIndex, s.roomsPerFloor, s.runId);
      const newFloorHP = calcRoomHP(newRoom);
      set({
        currentRoomIndex: newRoomIndex,
        currentRoom: newRoom,
        floorHP: newFloorHP,
        floorMaxHP: newFloorHP,
        castProgress: 0,
        weaponCastProgress: {},
      });
    }

    summonGolemsForRoom(get, set);

    // Handle non-combat rooms on ascent — initialize progress, do NOT auto-advance
    const room = get().currentRoom;
    if (room.roomType === 'library') {
      onEnterLibraryRoom(get, set);
    } else if (room.roomType === 'recovery') {
      onEnterRecoveryRoom(get, set);
    } else if (room.roomType === 'treasure') {
      onEnterTreasureRoom(get, set);
    } else if (room.roomType === 'puzzle') {
      onEnterPuzzleRoom(get, set);
    }
  }
}

// ─── Golem Summoning on Room Entry (spec §9.3) ──────────────────────────────

function summonGolemsForRoom(get: GetFn, set: SetFn): void {
  const s = get();
  const manaState = useManaStore.getState();
  const loadout = s.golemancy?.golemLoadout ?? [];
  if (loadout.length === 0) return;

  const attStore = useAttunementStore.getState();
  const fabLevel = attStore.attunements?.fabricator?.level ?? 0;
  const discEffects = computeDisciplineEffects();
  const discBonus = Math.floor(discEffects.bonuses.golemCapacity || 0);

  const currentActiveGolems = s.golemancy?.activeGolems ?? [];
  const summonResult = summonGolemsOnRoomEntry(
    loadout,
    manaState.rawMana,
    manaState.elements,
    s.currentFloor,
    currentActiveGolems,
    discBonus,
    fabLevel,
  );

  if (summonResult.logMessages.length > 0) {
    summonResult.logMessages.forEach((msg) => get().addActivityLog('special_effect', msg));
  }

  set({
    golemancy: { ...s.golemancy, activeGolems: summonResult.activeGolems },
  });

  useManaStore.setState({
    rawMana: summonResult.rawMana,
    elements: summonResult.elements,
  });
}

// ─── onEnterRoomDescend (climbing spec §4.7) ──────────────────────────────────

export function onEnterRoomDescend(get: GetFn, set: SetFn): void {
  const s = get();
  const key = `${s.currentFloor}:${s.currentRoomIndex}`;

  if (s.roomResetState[key] === undefined) {
    set((prev) => ({
      roomResetState: { ...prev.roomResetState, [key]: Math.random() < 0.5 },
    }));
  }

  const wasCleared = s.clearedRooms[key] === true;

  if (!wasCleared) {
    get().addActivityLog('floor_transition',
      `Floor ${s.currentFloor} Room ${s.currentRoomIndex + 1} was not cleared — enemies present`);

    // Initialize guardian defensive state for uncleared guardian rooms
    if (s.currentRoom.roomType === 'guardian') {
      const guardian = getGuardianForFloor(s.currentFloor);
      if (guardian) {
        set({
          guardianShield: guardian.shield ?? 0,
          guardianShieldMax: guardian.shield ?? 0,
          guardianBarrier: guardian.barrier ?? 0,
          guardianBarrierMax: guardian.barrier ?? 0,
        });
      }
    }

    // Initialize non-combat rooms during descent so they have proper progress tracking
    if (s.currentRoom.roomType === 'library') {
      onEnterLibraryRoom(get, set);
    } else if (s.currentRoom.roomType === 'recovery') {
      onEnterRecoveryRoom(get, set);
    } else if (s.currentRoom.roomType === 'treasure') {
      onEnterTreasureRoom(get, set);
    } else if (s.currentRoom.roomType === 'puzzle') {
      onEnterPuzzleRoom(get, set);
    }
    return;
  }

  const didReset = get().roomResetState[key];

  if (didReset) {
    const newRoom = generateSpireFloorState(s.currentFloor, s.currentRoomIndex, s.roomsPerFloor, s.runId);
    set({ currentRoom: newRoom, castProgress: 0, weaponCastProgress: {} });
    get().addActivityLog('floor_transition',
      `Floor ${s.currentFloor} Room ${s.currentRoomIndex + 1} has reset — enemies respawned`);

    if (newRoom.roomType === 'guardian') {
      const guardian = getGuardianForFloor(s.currentFloor);
      if (guardian) {
        set({
          guardianShield: guardian.shield ?? 0,
          guardianShieldMax: guardian.shield ?? 0,
          guardianBarrier: guardian.barrier ?? 0,
          guardianBarrierMax: guardian.barrier ?? 0,
        });
      }
    }
  } else {
    advanceRoomOrFloor(get, set);
  }
}

// ─── enterSpireMode (climbing spec §4.1) ──────────────────────────────────────

export function createEnterSpireMode(get: GetFn, set: SetFn) {
  return () => {
    const prestigeStore = usePrestigeStore.getState();
    const spireKey = prestigeStore.prestigeUpgrades.spireKey || 0;
    const startFloor = 1 + (spireKey * 2);
    const runId = Math.floor(Math.random() * 2147483647);
    const seed = startFloor * 12345 + runId;
    const rooms = getRoomsForFloor(startFloor, seed);
    const freshRoom = generateSpireFloorState(startFloor, 0, rooms, runId);

    set({
      spireMode: true,
      currentAction: 'climb',
      currentFloor: startFloor,
      startFloor,
      exitFloor: startFloor,
      runId,
      currentRoomIndex: 0,
      roomsPerFloor: rooms,
      floorHP: calcRoomHP(freshRoom),
      floorMaxHP: calcRoomHP(freshRoom),
      currentRoom: freshRoom,
      castProgress: 0,
      weaponCastProgress: {},
      climbDirection: 'up',
      isDescending: false,
      clearedFloors: {},
      clearedRooms: {},
      roomResetState: {},
      descentPeak: null,
      isDescentComplete: false,
      golemancy: { activeGolems: [], lastSummonFloor: 0, golemDesigns: get().golemancy?.golemDesigns ?? {}, golemLoadout: [] },
    });

    // Deactivate all active disciplines when entering the Spire
    useDisciplineStore.getState().deactivateAll();

    get().addActivityLog('floor_transition',
      `Entered the Spire at Floor ${startFloor}`);
  };
}
