/** ゲーム全体の可変状態。各シミュレーションモジュールはこれを受け取って更新する。 */
import {
  BREAK_PLANS,
  MILESTONES,
  SHIFT_TICKS,
  breakQuality,
  type BreakPlanId,
  type MilestoneDef,
  type MilestoneProgress,
} from '../core/config';
import type { Rng } from '../core/rng';
import type {
  Cat,
  DailyReport,
  Forklift,
  HazardKind,
  Incident,
  LogisticsRoute,
  PaperDoc,
  Phase,
  Tile,
} from '../core/types';

export interface LogEntry {
  tick: number;
  text: string;
  tone: 'info' | 'warn' | 'danger' | 'good';
}

export interface GameState {
  tiles: Tile[];
  cats: Cat[];
  rng: Rng;

  day: number;
  /** 当日の経過ティック (0..SHIFT_TICKS) */
  tick: number;
  phase: Phase;
  /** 稼働速度倍率 (1/2/4) */
  speed: number;

  money: number;
  /** 工場の信頼度 0..100。出荷単価に影響する。 */
  trust: number;

  itemSeq: number;
  catSeq: number;
  forkliftSeq: number;

  /** 稼働中のフォークリフト */
  forklifts: Forklift[];
  /** 本日フォークリフトが運んだパレット枚数 */
  palletsHauledToday: number;
  /** 本日荷役作業員が運んだカゴ荷役数 */
  basketsHandledToday: number;
  /** 本日フォークリフトが運んだコンテナ数 */
  containersHauledToday: number;
  /** 本日出発したトラックの台数 */
  truckDeparturesToday: number;
  /** 手作業運搬ライン (荷役・手すきの猫がピストン搬送するルート) */
  routes: LogisticsRoute[];

  // --- 技術開発 ---
  /** 貯まっている研究ポイント */
  researchPoints: number;
  /** 本日稼いだ研究ポイント */
  researchToday: number;
  /** 本日の素材調達費 */
  materialCostToday: number;
  /** 開発済みの技術ID */
  techs: string[];
  /** 搬入口が調達する素材のグレード */
  materialGrade: number;

  // --- 電力 ---
  /** その日の日射係数 (太陽光の出力に掛かる) */
  solarFactor: number;
  /** 電力が届いているマス (シフト開始時に算出) */
  powerCoverage: Uint8Array;
  /** 供給/需要の比 (1未満なら全機械が減速) */
  powerRatio: number;
  powerDemand: number;
  powerSupply: number;

  /** 達成済みマイルストーン数 (0 = 開始時のランク) */
  rank: number;
  /** 累計出荷数 */
  totalShipped: number;
  /** 重大事故ゼロの連続日数 */
  safeStreak: number;
  /** 宇宙船部品工場に到達したか */
  won: boolean;

  /** 未処理の書類。インシデントのたびに積まれ、事務机で処理される。 */
  paperwork: PaperDoc[];
  /** 本日処理した書類の数 */
  paperworkDoneToday: number;
  /** 選択中の定時休憩プラン */
  breakPlan: BreakPlanId;
  /** 休憩室の総マス数 (シフト開始時に算出) */
  breakRoomTiles: number;
  /** 最も広く繋がった休憩室のマス数 */
  breakRoomBest: number;

  /** 本日の労災件数 */
  injuriesToday: { injury: number; serious: number; fatal: number };
  /** 本日の治療費・補償の合計 */
  compensationToday: number;
  /** 労災ゼロの連続日数 (無災害記録) */
  safeDays: number;
  /** 累計の労災件数 */
  injuriesTotal: { injury: number; serious: number; fatal: number };

  shippedToday: number;
  defectsToday: number;
  revenueToday: number;
  damagesToday: number;
  incidentsToday: Incident[];

  /** ハザード種別ごとのリスクスコア 0..100 */
  risk: Record<HazardKind, number>;
  /** 改善策による低減率 0..1 */
  mitigation: Record<HazardKind, number>;
  /** 購入済みアップグレードID → 購入回数 */
  upgrades: Record<string, number>;

  log: LogEntry[];
  reports: DailyReport[];
  lastReport: DailyReport | null;
  gameOverReason: string | null;
}

/** 次に目指すマイルストーン。全て達成済みなら null。 */
export function nextMilestone(s: GameState): MilestoneDef | null {
  return MILESTONES[s.rank] ?? null;
}

export function milestoneProgress(s: GameState): MilestoneProgress {
  return {
    totalShipped: s.totalShipped,
    money: s.money,
    trust: s.trust,
    safeStreak: s.safeStreak,
    day: s.day,
  };
}

/** 現在のランクによる出荷単価倍率 */
export function priceMultiplier(s: GameState): number {
  return s.rank > 0 ? MILESTONES[s.rank - 1].priceMul : 1;
}

/** 現在のランクによる搬入速度倍率 */
export function intakeMultiplier(s: GameState): number {
  return s.rank > 0 ? MILESTONES[s.rank - 1].intakeMul : 1;
}

// ---------------------------------------------------------------- 定時休憩

/** 選択中の休憩プランの長さ (ティック) */
export function breakLength(s: GameState): number {
  return BREAK_PLANS.find((p) => p.id === s.breakPlan)?.ticks ?? 0;
}

/** 定時休憩の開始ティック (シフトの中ほど) */
export function breakStart(s: GameState): number {
  const len = breakLength(s);
  if (len <= 0) return -1;
  return Math.max(1, Math.floor((SHIFT_TICKS - len) / 2));
}

/** 今が定時休憩の時間帯か */
export function isBreakTime(s: GameState): boolean {
  const len = breakLength(s);
  if (len <= 0) return false;
  const start = breakStart(s);
  return s.tick >= start && s.tick < start + len;
}

/** 休憩室の広さから決まる回復倍率。休憩室が無ければ0。 */
export function breakRecovery(s: GameState): number {
  return breakQuality(s.breakRoomBest);
}

export function pushLog(s: GameState, text: string, tone: LogEntry['tone'] = 'info'): void {
  s.log.push({ tick: s.tick, text, tone });
  if (s.log.length > 240) s.log.splice(0, s.log.length - 240);
}

export function catById(s: GameState, id: number | null): Cat | null {
  if (id === null) return null;
  return s.cats.find((c) => c.id === id) ?? null;
}

/** 稼働可能な (休職中でない) 猫 */
export function activeCats(s: GameState): Cat[] {
  return s.cats.filter((c) => c.offDutyDays <= 0 && c.lives > 0);
}
