// ─── Non-Combat Room Actions ───────────────────────────────────────────────────
// Handles timed progression for Library, Recovery, Treasure, and Puzzle rooms.
// Extracted from combat-descent-actions.ts to stay under the 400-line limit.

import type { CombatState, CombatStore } from './combat-state.types';
import { useDisciplineStore } from './discipline-slice';
import { useManaStore } from './manaStore';
import { useAttunementStore } from './attunementStore';
import { MAX_ATTUNEMENT_LEVEL } from '../data/attunements';
import { PUZZLE_ROOMS } from '../constants';

type GetFn = () => CombatStore;
type SetFn = (state: Partial<CombatState>) => void;
type AdvanceFn = (get: GetFn, set: SetFn) => void;

// ─── Room Entry Handlers ──────────────────────────────────────────────────────

export function onEnterLibraryRoom(get: GetFn, set: SetFn): void {
  const s = get();
  set({
    currentRoom: {
      ...s.currentRoom,
      libraryProgress: 0,
      libraryRequired: 1,
      libraryStayed: false,
    },
  });
  get().addActivityLog('floor_transition',
    `Entered library room on Floor ${s.currentFloor}`);
}

export function onEnterRecoveryRoom(get: GetFn, set: SetFn): void {
  const s = get();
  set({
    currentRoom: {
      ...s.currentRoom,
      recoveryProgress: 0,
      recoveryRequired: 1,
      recoveryStayed: false,
    },
  });
  get().addActivityLog('floor_transition',
    `Entered recovery room on Floor ${s.currentFloor}`);
}

export function onEnterTreasureRoom(get: GetFn, set: SetFn): void {
  const s = get();
  set({
    currentRoom: {
      ...s.currentRoom,
      treasureProgress: 0,
      treasureRequired: 1,
      treasureLootClaimed: [],
    },
  });
  get().addActivityLog('floor_transition',
    `Entered treasure room on Floor ${s.currentFloor}`);
}

export function onEnterPuzzleRoom(get: GetFn, set: SetFn): void {
  const s = get();
  const puzzleId = s.currentRoom.puzzleId || 'enchanter_trial';
  const puzzle = PUZZLE_ROOMS[puzzleId];
  const attunements = puzzle?.attunements ?? ['enchanter'];

  let baseHours: number;
  if (s.currentFloor <= 20) {
    baseHours = 4;
  } else if (s.currentFloor <= 50) {
    baseHours = 8;
  } else if (s.currentFloor <= 100) {
    baseHours = 16;
  } else {
    baseHours = 24;
  }

  const attunementStore = useAttunementStore.getState();
  const maxReduction = 0.9;
  const perAttunementShare = maxReduction / attunements.length;
  let totalReduction = 0;

  for (const attId of attunements) {
    const attState = attunementStore.attunements[attId];
    if (attState?.active) {
      const levelFraction = Math.min((attState.level || 1) / MAX_ATTUNEMENT_LEVEL, 1);
      totalReduction += perAttunementShare * levelFraction;
    }
  }

  totalReduction = Math.min(totalReduction, maxReduction);
  const requiredHours = baseHours * (1 - totalReduction);

  set({
    currentRoom: {
      ...s.currentRoom,
      puzzleProgress: 0,
      puzzleRequired: Math.max(0.5, requiredHours),
      puzzleId,
      puzzleAttunements: attunements,
    },
  });
  get().addActivityLog('floor_transition',
    `Entered puzzle room on Floor ${s.currentFloor} — ${puzzle?.name || puzzleId}`);
}

// ─── Tick Handlers ────────────────────────────────────────────────────────────

export function tickNonCombatRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void {
  const s = get();
  const rt = s.currentRoom.roomType as string;

  if (rt === 'library') {
    tickLibraryRoom(get, set, hours, advance);
  } else if (rt === 'recovery') {
    tickRecoveryRoom(get, set, hours, advance);
  } else if (rt === 'treasure') {
    tickTreasureRoom(get, set, hours, advance);
  } else if (rt === 'puzzle') {
    tickPuzzleRoom(get, set, hours, advance);
  }
}

function tickLibraryRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void {
  const s = get();
  const room = s.currentRoom;
  const progress = (room.libraryProgress || 0) + hours;
  const required = room.libraryRequired || 1;

  if (progress < required) {
    const BASE_LIBRARY_XP_PER_HOUR = 50;
    const xpGrant = Math.floor(BASE_LIBRARY_XP_PER_HOUR * 25 * hours);

    if (xpGrant > 0) {
      const disciplineStore = useDisciplineStore.getState();
      const allDisciplines = disciplineStore.disciplines;
      const entries = Object.entries(allDisciplines).filter(([, ds]) => ds && !ds.paused);

      if (entries.length > 0) {
        const [targetId, targetDs] = entries[Math.floor(Math.random() * entries.length)];
        useDisciplineStore.setState((prev) => ({
          disciplines: {
            ...prev.disciplines,
            [targetId]: { ...targetDs, xp: (targetDs?.xp || 0) + xpGrant },
          },
          totalXP: prev.totalXP + xpGrant,
        }));
        get().addActivityLog('special_effect',
          `${targetDs?.id || targetId} gained ${xpGrant} XP from studying ancient tomes`);
      }
    }
  }

  if (progress >= required) {
    set({ currentRoom: { ...room, libraryProgress: progress } });
    get().addActivityLog('special_effect', 'Library study complete');
    advance(get, set);
  } else {
    set({ currentRoom: { ...room, libraryProgress: progress } });
  }
}

function tickRecoveryRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void {
  const s = get();
  const room = s.currentRoom;
  const progress = (room.recoveryProgress || 0) + hours;
  const required = room.recoveryRequired || 1;

  if (progress >= required) {
    set({ currentRoom: { ...room, recoveryProgress: progress } });
    get().addActivityLog('special_effect', 'Recovery complete — mana regen and conversion boosted');
    advance(get, set);
  } else {
    set({ currentRoom: { ...room, recoveryProgress: progress } });
  }
}

function tickTreasureRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void {
  const s = get();
  const room = s.currentRoom;
  const progress = (room.treasureProgress || 0) + hours;
  const required = room.treasureRequired || 1;
  const loot = room.treasureLoot || [];
  const claimed = room.treasureLootClaimed || [];

  if (progress >= required) {
    set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: claimed } });
    get().addActivityLog('special_effect', `Treasure room looted — ${claimed.length} items recovered`);
    advance(get, set);
    return;
  }

  const thresholds = [0.10, 0.50, 0.95, 1.0];
  const newlyClaimed: number[] = [];
  const claimedSet = new Set(claimed);

  for (const threshold of thresholds) {
    if (progress / required >= threshold) {
      const targetCount = Math.min(Math.ceil(loot.length * threshold), loot.length);
      for (let i = 0; i < targetCount; i++) {
        if (!claimedSet.has(i)) {
          claimedSet.add(i);
          newlyClaimed.push(i);
        }
      }
    }
  }

  for (const idx of newlyClaimed) {
    const drop = loot[idx];
    if (!drop) continue;

    if (drop.type === 'material' || drop.type === 'gold') {
      const amount = drop.amount
        ? Math.floor(Math.random() * (drop.amount.max - drop.amount.min + 1) + drop.amount.min)
        : 1;
      useManaStore.getState().addRawMana(amount, 999999);
      get().addActivityLog('special_effect', `Found ${amount}x ${drop.name}`);
    } else if (drop.type === 'essence') {
      const elementMap: Record<string, string> = {
        fireEssenceDrop: 'fire', waterEssenceDrop: 'water', airEssenceDrop: 'air',
        earthEssenceDrop: 'earth', lightEssenceDrop: 'light', darkEssenceDrop: 'dark',
        deathEssenceDrop: 'death',
      };
      const elem = elementMap[drop.id];
      if (elem) {
        const elemState = useManaStore.getState().elements[elem];
        if (elemState) {
          const amount = drop.amount
            ? Math.floor(Math.random() * (drop.amount.max - drop.amount.min + 1) + drop.amount.min)
            : 1;
          useManaStore.getState().addElementMana(elem, amount, elemState.max);
          get().addActivityLog('special_effect', `Found ${amount}x ${drop.name}`);
        }
      }
    } else if (drop.type === 'blueprint') {
      get().addActivityLog('special_effect', `Found blueprint: ${drop.name}`);
    }
  }

  set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: Array.from(claimedSet) } });
}

function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void {
  const s = get();
  const room = s.currentRoom;
  const progress = (room.puzzleProgress || 0) + hours;
  const required = room.puzzleRequired || 1;

  if (progress >= required) {
    set({ currentRoom: { ...room, puzzleProgress: progress } });
    get().addActivityLog('puzzle_solved', 'Puzzle solved!');
    advance(get, set);
  } else {
    set({ currentRoom: { ...room, puzzleProgress: progress } });
  }
}

// ─── Player Actions ───────────────────────────────────────────────────────────

export function skipNonCombatRoom(get: GetFn, set: SetFn, advance: AdvanceFn): void {
  const s = get();
  const rt = s.currentRoom.roomType as string;
  if (rt === 'library' || rt === 'recovery' || rt === 'treasure') {
    get().addActivityLog('floor_transition', `Skipped ${rt} room on Floor ${s.currentFloor}`);
    advance(get, set);
  }
}

export function stayLongerInRoom(get: GetFn, set: SetFn): void {
  const s = get();
  const room = s.currentRoom;
  const rt = room.roomType as string;

  if (rt === 'library' && !room.libraryStayed) {
    set({
      currentRoom: {
        ...room,
        libraryRequired: (room.libraryRequired || 1) + 1,
        libraryStayed: true,
      },
    });
    get().addActivityLog('special_effect', 'Decided to study for 1 more hour in the library');
  } else if (rt === 'recovery' && !room.recoveryStayed) {
    set({
      currentRoom: {
        ...room,
        recoveryRequired: (room.recoveryRequired || 1) + 1,
        recoveryStayed: true,
      },
    });
    get().addActivityLog('special_effect', 'Decided to rest for 1 more hour in the recovery room');
  }
}
