import type { AppState, StateRepository } from '@domain/ports/StateRepository';
import type { EventBus } from '@domain/events/EventBus';
import { GAUGE_DEFS, STAT_DEFS } from '@domain/value-objects/GaugeType';
import { computeGaugeState } from '@domain/services/GaugeCalculator';
import { xpForLevel, levelFromXp } from '@domain/value-objects/XpTable';

export interface CompleteTimerCommand { type: 'complete-timer'; enclosId: number; }

export function createCompleteTimerHandler(state: AppState, repo: StateRepository, events: EventBus) {
  return (cmd: CompleteTimerCommand): void => {
    const enc = state.enclos.find(e => e.id === cmd.enclosId);
    if (!enc || !enc.timer.running || enc.alerted['__done__']) return;

    const now = Date.now();
    enc.timer.running = false;
    enc.timer.pausedAt = now;
    enc.alerted['__done__'] = true;

    // Persister les stats finales de chaque DD dans dd.stats
    // pour que la session suivante parte des bonnes valeurs.
    const el = (now - enc.timer.startTime! - enc.timer.pausedMs) / 1000;
    for (const dd of enc.dragodindes) {
      for (const gid of enc.activeGauges) {
        const def = GAUGE_DEFS[gid];
        const startGl = enc.timer.snapGauges[gid] ?? enc.gaugeLevels[gid];
        const startSt = (enc.timer.snapStats[dd.id]?.[def.stat] ?? (dd.stats as Record<string, number>)[def.stat]) as number;
        const recharges = enc.timer.gaugeRecharges[gid] ?? [];

        let pts: number;
        if (def.isXp) {
          pts = Math.max(0, xpForLevel(200) - xpForLevel(startSt));
        } else {
          const sd = STAT_DEFS[def.stat];
          pts = def.dir > 0 ? Math.max(0, sd.max - startSt) : Math.max(0, startSt - sd.min);
        }

        const { gained } = computeGaugeState(startGl, recharges, pts, el);

        if (def.isXp) {
          dd.stats.xp = Math.min(200, Math.max(1, levelFromXp(xpForLevel(startSt) + gained)));
        } else {
          const sd = STAT_DEFS[def.stat];
          const raw = startSt + def.dir * gained;
          (dd.stats as Record<string, number>)[def.stat] = Math.min(sd.max, Math.max(sd.min, Math.round(raw)));
        }
      }
    }

    repo.save(state);
    events.emit({ type: 'timer-completed', enclosName: enc.name });
  };
}
