/** バランス調整用の定数と、ハザード／改善策のマスタデータ */
import type { HarmLevel, HazardKind, IncidentSeverity, TileKind } from './types';

export const GRID_W = 28;
export const GRID_H = 18;
export const TILE = 32;

/** 1シフト (=1日) の長さ。60fps 換算で約30秒。 */
export const SHIFT_TICKS = 1800;

export const START_MONEY = 60000;
export const PRICE_PER_GOOD = 1400;
/** 不良品は廃棄コストが発生する */
export const DEFECT_PENALTY = 300;
/** 猫1匹あたりの日給 (おやつ代) */
export const WAGE_PER_CAT = 1800;
/** 機械1台あたりの日次電気代 */
export const UTILITY_PER_MACHINE = 120;

// ---------------------------------------------------------------- 事務作業・休憩時間

/** 書類1件の処理に要する基準ティック (深刻度別) */
export const PAPER_WORK_TICKS: Record<IncidentSeverity, number> = {
  nearmiss: 70,
  minor: 130,
  injury: 180,
  serious: 240,
  fatal: 320,
};

/**
 * 書類を1件処理したときに下がるリスクスコア。
 * 発生時の上昇量より小さくしてあるので、事務作業だけでは火種は消えない。
 * 根本的に下げるには Action フェーズで対策を打つ必要がある。
 */
export const PAPER_RISK_RELIEF: Record<IncidentSeverity, number> = {
  nearmiss: 2,
  minor: 4,
  injury: 5,
  serious: 7,
  fatal: 9,
};

/** 未処理のまま持ち越した書類1件あたりの是正費用 */
export const PAPER_FINE = 450;
/** 1日に是正費用を請求される件数の上限。溜めすぎても立て直せる余地を残す。 */
export const PAPER_FINE_CAP = 16;
/** 書類がこの数を超えて滞留すると「書類の滞留」ハザードが発生する */
export const PAPER_BACKLOG_LIMIT = 8;

export interface BreakPlanDef {
  id: BreakPlanId;
  label: string;
  /** 休憩時間の長さ (ティック) */
  ticks: number;
  desc: string;
}

export type BreakPlanId = 'none' | 'short' | 'normal' | 'long';

/** 定時休憩の設定。長くするほど回復するが、そのぶんラインが止まる。 */
export const BREAK_PLANS: BreakPlanDef[] = [
  { id: 'none', label: '休憩なし', ticks: 0, desc: 'ラインは止まらないが、猫の機嫌と体力が回復しない。' },
  { id: 'short', label: '短い休憩', ticks: 170, desc: '約3秒。滞留は起きにくいが回復はほどほど。' },
  { id: 'normal', label: '標準の休憩', ticks: 300, desc: '約5秒。しっかり回復するぶん作業台の前に部品が溜まる。' },
  { id: 'long', label: '長い休憩', ticks: 450, desc: '約7.5秒。機嫌は大きく回復するが、生産は確実に落ちる。' },
];

/** 休憩室の広さから回復倍率を求める。部屋として繋げるほど効く。 */
export function breakQuality(largestRoom: number): number {
  if (largestRoom <= 0) return 0;
  return 0.55 + Math.min(largestRoom, 10) * 0.06;
}

/** 加工に必要なステージ数。stage>=FINAL_STAGE で完成品。 */
export const FINAL_STAGE = 2;

// ---------------------------------------------------------------- 電力

/** 配電盤が覆う範囲 (チェビシェフ距離) */
export const POLE_RADIUS = 5;
/** 系統から買える基本契約電力 */
export const GRID_CONTRACT = 14;
/** 系統電力の1単位あたりの日次料金 */
export const GRID_PRICE = 260;

/**
 * タイル1枚あたりの消費電力。
 * 加工機械は MACHINES の power をそのまま使い、それ以外はここで決める。
 */
export function tilePowerDraw(kind: TileKind): number {
  const m = MACHINES[kind];
  if (m) return m.power;
  switch (kind) {
    case 'conveyor':
      return 0.2;
    case 'splitter':
    case 'merger':
      return 0.3;
    case 'stocker':
      return 0.2;
    case 'feeder':
    case 'office':
    case 'lab':
      return 0.5;
    case 'handler_post':
      return 0.3;
    case 'dock':
      return 1.2;
    case 'forkdepot':
      return 1;
    default:
      return 0;
  }
}

export interface GeneratorDef {
  label: string;
  /** 発電量 */
  output: number;
  /** 1日あたりの燃料費 */
  fuel: number;
  /** 天候で出力が変わるか */
  weatherDependent: boolean;
}

/** 自家発電設備。燃料費は定額なので、需要が大きいほど系統より得になる。 */
export const GENERATORS: Record<string, GeneratorDef> = {
  generator: { label: 'ディーゼル発電機', output: 12, fuel: 4200, weatherDependent: false },
  solar: { label: '太陽光パネル', output: 5, fuel: 0, weatherDependent: true },
};

// ---------------------------------------------------------------- 製造機械

export interface MachineDef {
  kind: TileKind;
  label: string;
  /** 基準の加工ティック。小さいほど速い。 */
  workTicks: number;
  /** 猫を割り当てる必要があるか (アームロボットだけ不要) */
  needsOperator: boolean;
  /** 電気代の倍率 */
  power: number;
  /** 加工ミスによる不良率の倍率 */
  defectFactor: number;
  /** 1回の加工で稼げる加工精度。高グレードの製品ほど多く必要になる。 */
  precision: number;
  /** この機械を通した製品が梱包済みになるか */
  packs: boolean;
  /** この機械に固有の労災。無ければ null。 */
  hazard: HazardKind | null;
  /** 稼働1ティックあたりの労災ハザード発生率 */
  hazardRate: number;
}

/**
 * 加工機械。どれも「入力バッファから1個取り、加工段階を1つ上げる」点は同じで、
 * 速度・電力・危険性・仕上がりで性格を分けている。
 */
export const MACHINES: Record<string, MachineDef> = {
  bench: {
    kind: 'bench', label: '作業台', workTicks: 70, needsOperator: true,
    power: 1, defectFactor: 1, precision: 1, packs: false, hazard: null, hazardRate: 0,
  },
  lathe: {
    kind: 'lathe', label: '旋盤', workTicks: 46, needsOperator: true,
    power: 2.5, defectFactor: 1.4, precision: 1, packs: false,
    hazard: 'lathe_entangle', hazardRate: 0.0013,
  },
  press: {
    kind: 'press', label: 'プレス機', workTicks: 64, needsOperator: true,
    power: 2.2, defectFactor: 0.35, precision: 3, packs: false,
    hazard: 'press_crush', hazardRate: 0.001,
  },
  robot: {
    kind: 'robot', label: 'アームロボット', workTicks: 40, needsOperator: false,
    power: 4.5, defectFactor: 0.6, precision: 3, packs: false,
    hazard: 'robot_strike', hazardRate: 0.0018,
  },
  packer: {
    kind: 'packer', label: '梱包機', workTicks: 92, needsOperator: true,
    power: 1.6, defectFactor: 0.8, precision: 0, packs: true,
    hazard: 'packer_trap', hazardRate: 0.0008,
  },
};

/** タイル種別が加工機械か */
export function machineDef(kind: TileKind): MachineDef | null {
  return MACHINES[kind] ?? null;
}

/** 梱包された完成品の単価倍率 */
export const PACKED_PRICE_BONUS = 1.2;

export const BENCH_QUEUE_CAP = 5;
/** 入力バッファが満杯のままこのティック数を超えるとパニック判定に入る */
export const OVERFLOW_GRACE_TICKS = 200;
/** 作業台の基準加工時間 (ティック) */
export const BASE_WORK_TICKS = 70;
/** 搬入口のスポーン間隔。1本の直線ラインが作業台の処理速度と釣り合う程度に設定してある。 */
export const INTAKE_INTERVAL = 90;
/** コンベアが1タイル進むのに要するティック */
export const CONVEYOR_TICKS = 9;

/** 合流機が抱える待避スロット数。ここが「早い者勝ち」を緩和して合流を公平にする。 */
export const MERGER_CAP = 3;

/** ストッカー1段あたりの在庫上限 */
export const STOCKER_CAP = 8;

// ---------------------------------------------------------------- 段積み・パレット・輸送・容器

/** 段積みの上限 (三段まで) */
export const MAX_TIERS = 3;
/** 1段増やすたびにかかる費用 */
export const TIER_COST = 900;

/** パレット1段あたりに載る個数 */
export const PALLET_TIER = 6;
/** パレットを積み下ろしするのに要するティック */
export const PALLET_HANDLE_TICKS = 38;

/** カゴ1段あたりに載る個数 */
export const BASKET_TIER = 4;
export const BASKET_CAP = 4;
/** カゴが自動払い出しする間隔 */
export const BASKET_INTERVAL = 8;

/** コンテナ1個あたりの積載上限 (段積み不可) */
export const CONTAINER_CAP = 12;
export const CONTAINER_HANDLE_TICKS = 50;

/** 荷役作業員が一度に運べる上限個数 (素手の場合) */
export const HANDLER_CARRY_CAP = 4;
/** 荷役作業員が荷を拾い上げるティック */
export const HANDLER_PICK_TICKS = 24;
/** 荷役作業員が荷を置くティック */
export const HANDLER_DROP_TICKS = 18;

/** 荷役機材の定義 */
export const HANDLER_EQUIPMENT = {
  none:      { label: '素手',           cost: 0,    carryCap: 4,  speedMult: 1.0  },
  handcart:  { label: '台車',           cost: 2500, carryCap: 8,  speedMult: 0.85 },
  handfork:  { label: 'ハンドフォーク', cost: 4500, carryCap: 12, speedMult: 0.70 },
} as const;

/** フォークリフトの走行速度 (タイル/ティック) */
export const FORKLIFT_SPEED = 0.12;

/** トラック1台に積める個数 */
export const TRUCK_CAP = 12;
/** 1個を積み込むのに要する基準ティック */
export const LOAD_TICKS = 26;
/** トラックが出発してから次の車が着くまでのティック */
export const TRUCK_SWAP_TICKS = 150;
/** トラックでまとめて出荷したときの単価倍率 */
export const TRUCK_PRICE_BONUS = 1.25;

/** 段数と積載率から崩落ハザードの発生率を求める。一段積みなら崩れない。 */
export function collapseRate(tiers: number, fillRatio: number): number {
  if (tiers <= 1) return 0;
  return (tiers - 1) * 0.00022 * (0.35 + fillRatio);
}
/** ストッカーが1個払い出すのに要するティック */
export const STOCKER_INTERVAL = 5;

export interface BuildDef {
  kind: TileKind;
  label: string;
  cost: number;
  /** 電気代の対象になるか */
  machine: boolean;
  desc: string;
  hotkey: string;
}

/** 建設パレット。PLANフェーズで設置できるもの。 */
export const BUILDS: BuildDef[] = [
  { kind: 'conveyor', label: 'コンベア',           cost: 320,  machine: true,  hotkey: '1', desc: 'クリックで設置、同じマスを再クリックで向き変更。モノの動線。' },
  { kind: 'splitter', label: '分岐機（スプリッター）', cost: 1100, machine: true,  hotkey: '2', desc: '背面から受け取り、正面・左・右へ順番に振り分ける。1本のラインを複数系統へ。' },
  { kind: 'merger',   label: '合流機（マージャー）',   cost: 1100, machine: true,  hotkey: '3', desc: '複数方向から受け取り、正面へ流す。待避スロットを持つので合流が公平になる。' },
  { kind: 'stocker',  label: '一時保管ストッカー',   cost: 1400, machine: true,  hotkey: '4', desc: '1段8個まで溜めて放出する「遊び」。猫の作業ペースのムラを吸収する。' },
  { kind: 'pallet',   label: 'パレット置き場',     cost: 1100, machine: false, hotkey: 'v', desc: '1段6個で1パレット。満載になるとフォークリフトがトラックバースへ運ぶ。' },
  { kind: 'basket',   label: 'カゴ置き場',         cost: 600,  machine: false, hotkey: 'y', desc: '1段4個。小型の網カゴ。荷役作業員が手作業で運搬できる。' },
  { kind: 'container', label: '大型コンテナ',      cost: 2800, machine: false, hotkey: 'u', desc: '12個収容の大型鉄製コンテナ。大容量だがフォークリフト輸送が必要。' },
  { kind: 'handler_post', label: '荷役ステーション', cost: 1800, machine: true,  hotkey: 'n', desc: '猫を1匹割り当てて荷役作業員にする。手作業でカゴや置き場から製品を運ぶ。' },
  { kind: 'forkdepot', label: 'フォークリフト詰所', cost: 7200, machine: true,  hotkey: 'f', desc: '猫を1匹割り当てて運転手にする。走行にはコンベアの無い通路が必要。' },
  { kind: 'dock',     label: 'トラックバース',     cost: 6000, machine: true,  hotkey: 'd', desc: '猫を1匹割り当てて積み込み作業。12個でトラックが出発し、単価+25%で出荷される。' },
  { kind: 'bench',    label: '作業台',             cost: 2600, machine: true,  hotkey: '5', desc: '汎用の加工台。遅いが安全で電気も食わない。猫を1匹割り当てる。' },
  { kind: 'lathe',    label: '旋盤',               cost: 4200, machine: true,  hotkey: 'l', desc: '作業台の1.5倍速。ただし回転部にしっぽを巻き込まれる労災が起きる。' },
  { kind: 'press',    label: 'プレス機',           cost: 5000, machine: true,  hotkey: 'p', desc: '精度が高く不良品がほぼ出ない。挟まれによる重篤な労災に注意。' },
  { kind: 'robot',    label: 'アームロボット',     cost: 9500, machine: true,  hotkey: 'r', desc: '猫の割り当て不要で最速。電気代は作業台の4.5倍。可動範囲の猫に激突する。' },
  { kind: 'packer',   label: '梱包機',             cost: 4800, machine: true,  hotkey: 'k', desc: '遅いが、通した完成品は梱包済みとなり単価が2割上がる。猫が中に入り込む。' },
  { kind: 'rest',     label: '仮眠クッション',     cost: 900,  machine: false, hotkey: '6', desc: '疲れた猫がその都度倒れ込む場所。体力と機嫌を回復する。' },
  { kind: 'breakroom', label: '休憩室',            cost: 800,  machine: false, hotkey: 'b', desc: '定時休憩で猫が集まる部屋。隣り合わせて広くするほど回復量が上がる。1マスに1匹。' },
  { kind: 'office',   label: '事務机（事務室）',   cost: 2200, machine: true,  hotkey: 'o', desc: '猫を割り当てて事務作業をさせる。ヒヤリハット報告書を処理してリスクを下げる。' },
  { kind: 'lab',      label: '開発室',             cost: 3000, machine: true,  hotkey: 'e', desc: '猫を割り当てて研究ポイントを稼ぐ。開発ツリーを進めると扱える機械と素材が増える。' },
  { kind: 'pole',     label: '配電盤',             cost: 1600, machine: false, hotkey: 'g', desc: `半径${POLE_RADIUS}マスへ送電する。範囲外の機械は動かない。` },
  { kind: 'generator', label: 'ディーゼル発電機',  cost: 9000, machine: false, hotkey: 'h', desc: '発電量12。燃料費は1日¥4,200の定額。' },
  { kind: 'solar',    label: '太陽光パネル',       cost: 7000, machine: false, hotkey: 'j', desc: '発電量5。燃料費はかからないが、その日の天候で出力が55〜100%に振れる。' },
  { kind: 'litter',   label: 'トイレ',             cost: 700,  machine: false, hotkey: '7', desc: '尿意を解消。行けないと機嫌が崩壊する。' },
  { kind: 'scratch',  label: '爪とぎタワー',       cost: 1200, machine: false, hotkey: '8', desc: 'ヘイトを機械から逸らすデコイ。破壊衝動の受け皿。' },
  { kind: 'feeder',   label: '自動給餌器',         cost: 1500, machine: true,  hotkey: '9', desc: '空腹を解消して機嫌を回復させる。' },
  { kind: 'box',      label: '段ボール箱',         cost: 500,  machine: false, hotkey: '0', desc: '暴走した猫を吸い込んで鎮静化させる最強のトラップ。' },
  { kind: 'wall',     label: '壁',                 cost: 150,  machine: false, hotkey: 'w', desc: '猫の侵入を物理的に防ぐ。動線の分断に注意。' },
  { kind: 'floor',    label: '撤去',               cost: 0,    machine: false, hotkey: 'x', desc: '設置物を撤去する (建設費の3割が戻る)。' },
];

/** キャットウォークは既存タイルへの重ね掛けなので別枠。 */
export const CATWALK_COST = 450;

// ---------------------------------------------------------------- マイルストーン

/** マイルストーン判定に使う進捗のスナップショット */
export interface MilestoneProgress {
  totalShipped: number;
  money: number;
  trust: number;
  /** 重大事故ゼロの連続日数 */
  safeStreak: number;
  day: number;
}

export interface MilestoneDef {
  id: string;
  /** 到達後の工場ランク名 */
  label: string;
  /** 達成条件の説明文 */
  goal: string;
  /** 達成時の一時金 */
  reward: number;
  /** 到達後の出荷単価倍率 */
  priceMul: number;
  /** 到達後の搬入速度倍率 (大きいほど資材が速く届く) */
  intakeMul: number;
  /** 到達後に解禁される内容の説明 */
  unlock: string;
  check(p: MilestoneProgress): boolean;
  /** 進捗表示用: 0..1 */
  progress(p: MilestoneProgress): number;
}

/** 開始時のランク名 */
export const INITIAL_RANK = 'おやつ代稼ぎ';

const ratio = (a: number, b: number): number => Math.max(0, Math.min(1, a / b));

/** 小さな町工場から宇宙船部品工場までの成長ライン。 */
export const MILESTONES: MilestoneDef[] = [
  {
    id: 'town', label: '町工場', goal: '累計出荷 30個',
    reward: 8000, priceMul: 1.1, intakeMul: 1.25,
    unlock: '取引先が付き、出荷単価 +10% / 資材の搬入が 1.25倍速に',
    check: (p) => p.totalShipped >= 30,
    progress: (p) => ratio(p.totalShipped, 30),
  },
  {
    id: 'mid', label: '中堅工場', goal: '累計出荷 100個 かつ 資金 ¥100,000',
    reward: 20000, priceMul: 1.25, intakeMul: 1.6,
    unlock: '出荷単価 +25% / 搬入 1.6倍速',
    check: (p) => p.totalShipped >= 100 && p.money >= 100000,
    progress: (p) => (ratio(p.totalShipped, 100) + ratio(p.money, 100000)) / 2,
  },
  {
    id: 'auto', label: '自動化工場', goal: '累計出荷 250個 かつ 無災害 5日連続',
    reward: 45000, priceMul: 1.4, intakeMul: 2.0,
    unlock: '出荷単価 +40% / 搬入 2倍速',
    check: (p) => p.totalShipped >= 250 && p.safeStreak >= 5,
    progress: (p) => (ratio(p.totalShipped, 250) + ratio(p.safeStreak, 5)) / 2,
  },
  {
    id: 'precision', label: '精密機器工場', goal: '累計出荷 450個 かつ 信頼度 95以上',
    reward: 80000, priceMul: 1.6, intakeMul: 2.4,
    unlock: '出荷単価 +60% / 搬入 2.4倍速',
    check: (p) => p.totalShipped >= 450 && p.trust >= 95,
    progress: (p) => (ratio(p.totalShipped, 450) + ratio(p.trust, 95)) / 2,
  },
  {
    id: 'spacecraft', label: '宇宙船部品工場', goal: '累計出荷 700個 かつ 資金 ¥400,000',
    reward: 0, priceMul: 2.0, intakeMul: 2.8,
    unlock: 'ゲームクリア',
    check: (p) => p.totalShipped >= 700 && p.money >= 400000,
    progress: (p) => (ratio(p.totalShipped, 700) + ratio(p.money, 400000)) / 2,
  },
];

// ---------------------------------------------------------------- 労働災害

/** 人身災害の段階ごとの扱い */
export interface HarmRule {
  label: string;
  /** 治療費・補償 */
  cost: number;
  /** 休業日数の範囲 */
  offDuty: [number, number];
  /** 信頼度の低下 */
  trustLoss: number;
  /** 9つの命を消費するか */
  costsLife: boolean;
}

export const HARM_RULES: Record<'injury' | 'serious' | 'fatal', HarmRule> = {
  injury: {
    label: '軽傷', cost: 3000, offDuty: [1, 2], trustLoss: 3, costsLife: false,
  },
  serious: {
    label: '重傷', cost: 15000, offDuty: [3, 5], trustLoss: 9, costsLife: false,
  },
  fatal: {
    label: '死亡', cost: 40000, offDuty: [5, 7], trustLoss: 25, costsLife: true,
  },
};

/** 深刻度の日本語表記 */
export const SEVERITY_LABEL: Record<IncidentSeverity, string> = {
  nearmiss: 'ヒヤリ',
  minor: '物損事故',
  injury: '軽傷',
  serious: '重傷',
  fatal: '死亡事故',
};

export interface HazardDef {
  kind: HazardKind;
  label: string;
  /** ヒヤリハット時の文面テンプレート */
  nearmiss: string;
  /** 物損事故に発展した時の文面テンプレート */
  accident: string;
  /** 人身災害に至った時の文面テンプレート */
  harmText?: string;
  /** 事故に発展した際の基本損害額 */
  damage: number;
  /** この事案が至りうる人身災害の上限 */
  harm: HarmLevel;
  /**
   * 重篤化のしやすさ。回転体や挟まれのある機械は同じリスクスコアでも
   * 一気に人身災害へ跳ねるので、1より大きい値を持たせる。
   */
  harmBias?: number;
  /** 対策の説明 (日報の提言に出す) */
  advice: string;
}

export const HAZARDS: Record<HazardKind, HazardDef> = {
  sleep_on_line: {
    kind: 'sleep_on_line', label: 'ライン上での就寝',
    nearmiss: '{cat} が稼働中のコンベア上で寝転がっていた',
    accident: '{cat} の尻尾がコンベアに巻き込まれた',
    harmText: '{cat} の尻尾がコンベアに巻き込まれ、体ごと引き込まれた',
    damage: 2200, harm: 'serious', harmBias: 1.6,
    advice: '休憩所を増設し、ライン上にキャットウォークを敷いて動線を分離してください。',
  },
  cross_line: {
    kind: 'cross_line', label: 'ラインへの無断侵入',
    nearmiss: '{cat} がショートカットで稼働中のコンベアを横断した',
    accident: '{cat} がコンベア上で転倒し、搬送中の製品が落下・破損した',
    harmText: '{cat} がコンベア上で転倒し、床に投げ出された',
    damage: 1400, harm: 'injury',
    advice: '休憩所・トイレへの正規ルートを確保するか、キャットウォークを敷設してください。',
  },
  no_helmet: {
    kind: 'no_helmet', label: 'ヘルメット未着用',
    nearmiss: '{cat} がヘルメットを脱ぎ捨てて作業していた',
    accident: '{cat} が無防備な状態で落下物を受けた',
    harmText: '{cat} が無防備な頭部に落下物を受けた',
    damage: 2200, harm: 'serious', harmBias: 1.3,
    advice: '記憶力の低い猫は手順を忘れます。機嫌を高く保つと遵守率が上がります。',
  },
  boiler_nap: {
    kind: 'boiler_nap', label: '立入禁止区域での就寝',
    nearmiss: '{cat} が立入禁止のボイラー室に侵入して寝ていた',
    accident: '過熱したボイラーが小規模な爆発を起こした',
    harmText: '過熱したボイラーが爆発し、{cat} が巻き込まれた',
    damage: 6000, harm: 'fatal', harmBias: 1.9,
    advice: 'ボイラーの周囲を壁で封鎖するか、より暖かい休憩所を近くに置いてください。',
  },
  scratch_machine: {
    kind: 'scratch_machine', label: '機械での爪とぎ',
    nearmiss: '{cat} が高価な工作機械で爪を研いでいた',
    accident: '{cat} が削った配線から作業台がショートし停止した',
    harmText: '{cat} が削った配線でショートが起き、感電した',
    damage: 2800, harm: 'injury',
    advice: '爪とぎタワーを作業台の近くに設置してヘイトを逸らしてください。',
  },
  overflow: {
    kind: 'overflow', label: 'オーバーフロー(パニック)',
    nearmiss: '{cat} の作業台に部品が殺到し、威嚇を始めた',
    accident: '{cat} がパニックで作業を放棄し、ラインが停止した',
    damage: 900, harm: 'none',
    advice: '一時保管ストッカー代わりの「遊び」を設けるか、上流の供給を絞ってください。',
  },
  cable_bite: {
    kind: 'cable_bite', label: '退屈による破壊行動',
    nearmiss: '{cat} が手持ち無沙汰で機械のケーブルを噛みかけた',
    accident: '{cat} がケーブルを噛みちぎり、作業台が故障した',
    harmText: '{cat} が噛んだケーブルから感電した',
    damage: 2400, harm: 'injury',
    advice: 'ボトルネックを解消するか、爪とぎタワーで暇を潰させてください。',
  },
  cat_punch: {
    kind: 'cat_punch', label: 'ネコパンチ・喧嘩',
    nearmiss: '{cat} が同僚に手を上げかけた',
    accident: '{cat} が同僚とつかみ合いの喧嘩になりラインが停止した',
    harmText: '{cat} が同僚との取っ組み合いで負傷した',
    damage: 1600, harm: 'injury',
    advice: '自動給餌器と休憩所で機嫌を維持し、段ボール箱を隔離用に配置してください。',
  },
  fur_contamination: {
    kind: 'fur_contamination', label: '製品への抜け毛混入',
    nearmiss: '{cat} が流れてくる製品を前足で弾いた',
    accident: '製品に抜け毛が混入し、不良品として廃棄された',
    damage: 500, harm: 'none',
    advice: 'キャットウォークでモノの動線と猫の動線を三次元的に分離してください。',
  },
  no_break: {
    kind: 'no_break', label: '休憩の未確保',
    nearmiss: '{cat} が休憩時間に休憩室へ入れず、通路で座り込んでいた',
    accident: '{cat} が休憩を取れないまま不満を爆発させ、積んであった資材を薙ぎ払った',
    harmText: '疲労の蓄積した {cat} が足を踏み外して転落した',
    damage: 1600, harm: 'injury',
    advice: '休憩室のマス数が従業員数に足りていません。広げるか、休憩時間の設定を見直してください。',
  },
  paperwork: {
    kind: 'paperwork', label: '書類の滞留',
    nearmiss: '未処理のヒヤリハット報告書が溜まり、対策の検討が止まっている',
    accident: '報告書の不備を指摘され、是正勧告を受けた',
    damage: 2400, harm: 'none',
    advice: '事務机を増やすか、事務作業に猫を割り当ててください。書類は放置するほどリスクが下がりません。',
  },
  lathe_entangle: {
    kind: 'lathe_entangle', label: '旋盤への巻き込まれ',
    nearmiss: '{cat} の尻尾が回転中の旋盤のチャックをかすめた',
    accident: '{cat} の毛が旋盤に絡まり、加工中の材料が飛散した',
    harmText: '{cat} が旋盤の回転部に巻き込まれた',
    damage: 2600, harm: 'fatal', harmBias: 2.3,
    advice: '旋盤は速いぶん危険です。回転部の安全カバーを付けるか、疲れた猫を担当から外してください。',
  },
  press_crush: {
    kind: 'press_crush', label: 'プレス機への挟まれ',
    nearmiss: '{cat} がプレス機の金型の上で丸くなっていた',
    accident: '{cat} が下降中のプレスに前足を掛け、金型を破損させた',
    harmText: '{cat} がプレス機に挟まれた',
    damage: 3200, harm: 'fatal', harmBias: 2.4,
    advice: '両手押しボタンや光線式の安全装置を導入してください。暖かい金型は猫を引き寄せます。',
  },
  robot_strike: {
    kind: 'robot_strike', label: 'アームロボットとの接触',
    nearmiss: 'アームロボットの可動範囲を {cat} が横切った',
    accident: 'アームロボットが {cat} を検知して非常停止し、ラインが止まった',
    harmText: 'アームロボットのアームが {cat} に激突した',
    damage: 2800, harm: 'fatal', harmBias: 2.1,
    advice: '可動範囲を壁で囲うか、周囲にキャットウォークを通して猫の動線を上へ逃がしてください。',
  },
  packer_trap: {
    kind: 'packer_trap', label: '梱包機への閉じ込め',
    nearmiss: '{cat} が梱包機の投入口を覗き込んでいた',
    accident: '{cat} が梱包機に入り込み、包装材を台無しにした',
    harmText: '{cat} が梱包機の中に閉じ込められたまま封をされた',
    damage: 2200, harm: 'fatal', harmBias: 1.8,
    advice: '猫は箱に入ります。投入口にセンサーを付けるか、近くに段ボール箱を置いて気を逸らしてください。',
  },
  forklift_run: {
    kind: 'forklift_run', label: 'フォークリフトとの接触',
    nearmiss: '{cat} がフォークリフトの進路上で寝転がっていた',
    accident: 'フォークリフトが {cat} を避けきれず、積荷を落とした',
    harmText: 'フォークリフトが {cat} を轢いた',
    damage: 3000, harm: 'fatal', harmBias: 2.2,
    advice: '走行通路を確保し、猫の動線と交差させないでください。キャットウォークで立体交差させるのが確実です。',
  },
  stack_collapse: {
    kind: 'stack_collapse', label: '積み荷の崩落',
    nearmiss: '三段積みの在庫が傾き、{cat} が慌てて飛び退いた',
    accident: '積み上げた在庫が崩れ、製品が床に散乱した',
    harmText: '崩れた積み荷の下敷きに {cat} がなった',
    damage: 2400, harm: 'fatal', harmBias: 1.7,
    advice: '段数を減らすか、満載のまま放置しないでください。二段目以降は崩れます。',
  },
  truck_load: {
    kind: 'truck_load', label: '積み込み作業中の災害',
    nearmiss: '{cat} がトラックの荷台の縁でよろけた',
    accident: '{cat} が積み込み中の荷を落として破損させた',
    harmText: '{cat} がトラックの荷台から転落した',
    damage: 2000, harm: 'serious', harmBias: 1.5,
    advice: '積み込みは体力を使います。休憩室を近くに置いて、疲れた猫に任せないでください。',
  },
  heavy_lifting: {
    kind: 'heavy_lifting', label: '重量物の手搬送・腰痛',
    nearmiss: '{cat} が重いカゴを持ち上げようとして腰を痛めかけた',
    accident: '{cat} が荷物を運搬中に足をもつれさせて転倒し、荷が破損した',
    harmText: '{cat} が重量物を抱えたまま転倒し負傷した',
    damage: 1800, harm: 'injury', harmBias: 1.2,
    advice: '荷役作業員に負担がかかっています。台車の導入やフォークリフトへの切り替えを検討してください。',
  },
  blackout: {
    kind: 'blackout', label: '停電',
    nearmiss: '電力が不足し、照明がちらついて {cat} が作業の手を止めた',
    accident: '電力不足で機械が一斉に停止し、加工中の材料が台無しになった',
    harmText: '暗転した工場で {cat} が機械に接触した',
    damage: 2600, harm: 'serious', harmBias: 1.4,
    advice: '発電設備を増やすか、稼働させる機械を減らしてください。契約電力を超えると全機械が減速します。',
  },
  blocked_route: {
    kind: 'blocked_route', label: '動線の分断',
    nearmiss: '{cat} が休憩所へ向かおうとしたが経路が見つからず立ち尽くした',
    accident: '{cat} の機嫌が限界に達し、資材を床に押し落として破壊した',
    damage: 1800, harm: 'none',
    advice: 'スパゲッティ・ラインになっています。通路かキャットウォークを確保してください。',
  },
};

export const HAZARD_KINDS = Object.keys(HAZARDS) as HazardKind[];

/**
 * 改善策。PDCAの Action は「日報に挙がった事案」に対してだけ打てるようにしてあるため、
 * それぞれの対策は必ず1つのハザード (target) に紐付いている。
 */
export interface CounterDef {
  id: string;
  /** この対策が対象とする事案。Actionフェーズでのグルーピングに使う。 */
  target: HazardKind;
  label: string;
  cost: number;
  desc: string;
  /** 併せて低減される事案 (target を含む) */
  mitigates: HazardKind[];
  /** リスク低減率 0..1 */
  reduction: number;
  /** 1回だけ買えるか */
  once: boolean;
}

/** 事案ごとの対策。日報で挙がった事案の下に並ぶ。 */
export const COUNTERS: CounterDef[] = [
  {
    id: 'line_stop', target: 'sleep_on_line', label: 'ライン緊急停止装置',
    cost: 9000, reduction: 0.6, once: true,
    mitigates: ['sleep_on_line', 'overflow'],
    desc: '巻き込みを検知してラインを止める。重大事故への発展を強く抑える。',
  },
  {
    id: 'crosswalk', target: 'cross_line', label: '通路の区画線と横断ルール',
    cost: 3800, reduction: 0.45, once: false,
    mitigates: ['cross_line'],
    desc: '正規ルートを床に描いて周知する。ショートカットの常態化を抑える。(重ねがけ可)',
  },
  {
    id: 'helmet_drill', target: 'no_helmet', label: '安全教育（毎朝の朝礼）',
    cost: 5200, reduction: 0.4, once: false,
    mitigates: ['no_helmet', 'cross_line'],
    desc: '猫の記憶力が回復し、ヘルメット着用率と手順遵守率が上がる。(重ねがけ可)',
  },
  {
    id: 'boiler_lock', target: 'boiler_nap', label: 'ボイラー室の施錠',
    cost: 7500, reduction: 0.8, once: true,
    mitigates: ['boiler_nap'],
    desc: '立入禁止区域への侵入を大幅に抑止する。',
  },
  {
    id: 'guard_sheet', target: 'scratch_machine', label: '機械への爪とぎ防止シート',
    cost: 3200, reduction: 0.45, once: false,
    mitigates: ['scratch_machine'],
    desc: '筐体に貼って爪の掛かりを無くす。研ぎ心地が悪ければ猫は諦める。(重ねがけ可)',
  },
  {
    id: 'leveling', target: 'overflow', label: '工程間の平準化',
    cost: 4600, reduction: 0.4, once: false,
    mitigates: ['overflow'],
    desc: '供給ペースと作業台の能力を突き合わせて調整する。殺到の頻度が下がる。(重ねがけ可)',
  },
  {
    id: 'cable_cover', target: 'cable_bite', label: '配線カバーの敷設',
    cost: 3600, reduction: 0.45, once: false,
    mitigates: ['cable_bite'],
    desc: 'ケーブルを覆って噛みちぎれないようにする。(重ねがけ可)',
  },
  {
    id: 'treats', target: 'cat_punch', label: '高級猫おやつの配給',
    cost: 4000, reduction: 0.35, once: false,
    mitigates: ['cat_punch', 'blocked_route', 'no_break'],
    desc: '全従業員の機嫌の下限が上がり、八つ当たりが減る。(重ねがけ可)',
  },
  {
    id: 'cleaner_bot', target: 'fur_contamination', label: 'お掃除ロボットの導入',
    cost: 6800, reduction: 0.5, once: true,
    mitigates: ['fur_contamination'],
    desc: '抜け毛を回収して混入を減らす。ただし猫が乗って遊ぶリスクあり。',
  },
  {
    id: 'flow_review', target: 'blocked_route', label: '動線の見直し（管理者の巡回）',
    cost: 4400, reduction: 0.4, once: false,
    mitigates: ['blocked_route'],
    desc: '塞がった通路を見つけて猫を誘導する。動線分断の影響を和らげる。(重ねがけ可)',
  },
  {
    id: 'shift_break', target: 'no_break', label: '休憩の交替制導入',
    cost: 3400, reduction: 0.45, once: true,
    mitigates: ['no_break'],
    desc: '休憩を2班に分ける。休憩室1マスあたり2匹まで入れるようになる。',
  },
  {
    id: 'lathe_guard', target: 'lathe_entangle', label: '旋盤の安全カバー設置',
    cost: 4200, reduction: 0.55, once: false,
    mitigates: ['lathe_entangle'],
    desc: '回転部を覆って毛や尻尾の巻き込みを防ぐ。(重ねがけ可)',
  },
  {
    id: 'two_hand', target: 'press_crush', label: '両手押しボタン式への改造',
    cost: 5400, reduction: 0.6, once: false,
    mitigates: ['press_crush'],
    desc: '前足を両方ボタンに置かないと下降しない。挟まれを構造的に防ぐ。(重ねがけ可)',
  },
  {
    id: 'robot_fence', target: 'robot_strike', label: 'ロボットの安全柵と光線センサー',
    cost: 6400, reduction: 0.65, once: false,
    mitigates: ['robot_strike'],
    desc: '可動範囲に猫が入ると停止する。停止するぶん生産は落ちるが激突は防げる。(重ねがけ可)',
  },
  {
    id: 'packer_sensor', target: 'packer_trap', label: '梱包機の投入口センサー',
    cost: 3900, reduction: 0.6, once: false,
    mitigates: ['packer_trap'],
    desc: '中に猫がいる間は封をしない。(重ねがけ可)',
  },
  {
    id: 'aisle', target: 'forklift_run', label: '走行通路の区画とミラー設置',
    cost: 4800, reduction: 0.55, once: false,
    mitigates: ['forklift_run'],
    desc: 'フォークリフトの走行帯を引き、交差部にミラーを付ける。(重ねがけ可)',
  },
  {
    id: 'stack_band', target: 'stack_collapse', label: '荷崩れ防止バンドの導入',
    cost: 3400, reduction: 0.55, once: false,
    mitigates: ['stack_collapse'],
    desc: '段ごとにバンドで固縛する。三段積みでも崩れにくくなる。(重ねがけ可)',
  },
  {
    id: 'dock_rail', target: 'truck_load', label: 'バースの安全柵と昇降台',
    cost: 3600, reduction: 0.6, once: false,
    mitigates: ['truck_load'],
    desc: '荷台の縁に柵を付け、昇降台を用意する。(重ねがけ可)',
  },
  {
    id: 'power_margin', target: 'blackout', label: '契約電力の増枠',
    cost: 5200, reduction: 0.5, once: false,
    mitigates: ['blackout'],
    desc: '系統からの受電容量を増やす。停電のリスクが下がる。(重ねがけ可)',
  },
  {
    id: 'outsource', target: 'paperwork', label: '事務代行サービスの契約',
    cost: 6200, reduction: 0.45, once: false,
    mitigates: ['paperwork'],
    desc: '毎朝、未処理書類の一部を代行処理してくれる。(重ねがけ可)',
  },
  {
    id: 'hand_cart', target: 'heavy_lifting', label: '運搬用台車の支給',
    cost: 4200, reduction: 0.55, once: false,
    mitigates: ['heavy_lifting'],
    desc: '荷役作業員に専用台車を支給する。手運びによる転倒や腰痛を抑える。(重ねがけ可)',
  },
];

/**
 * 体制の見直し。特定の事案に紐付かないので、事案が無くてもいつでも打てる。
 */
export const ORG_ACTIONS: CounterDef[] = [
  {
    id: 'safety_shoes', target: 'no_helmet', label: '保護具の一斉更新',
    cost: 5600, reduction: 0.3, once: false,
    mitigates: ['sleep_on_line', 'no_helmet', 'lathe_entangle', 'press_crush', 'robot_strike'],
    desc: 'ヘルメットと防護具を新調する。人身災害全般の重篤化を抑える。(重ねがけ可)',
  },
  {
    id: 'maintenance', target: 'cable_bite', label: '定期メンテナンス契約',
    cost: 5800, reduction: 0.3, once: false,
    mitigates: ['cable_bite', 'scratch_machine'],
    desc: '機械の故障時間が短縮され、破壊行動による損害が減る。(重ねがけ可)',
  },
  {
    id: 'hire', target: 'cat_punch', label: '新規採用（猫を1匹雇う）',
    cost: 8000, reduction: 0, once: false,
    mitigates: [],
    desc: '従業員を1匹増やす。ライン増設や事務作業の人手に。',
  },
];

/** 購入処理・低減率計算で使う全アクション */
export const ALL_ACTIONS: CounterDef[] = [...COUNTERS, ...ORG_ACTIONS];
