-- FF_STORY_COMPUTER_GUARD
local function ff_story_computer_allowed()
  local label = os.getComputerLabel and os.getComputerLabel() or nil
  return fs.exists(".ff_story_computer")
    or fs.exists(".ff_titan_computer")
    or fs.exists(".ff_titan_program_id")
    or fs.exists(".ff_titan_allow_autoinstall")
    or fs.exists(".ff_titan_allow_autorun")
    or (label ~= nil and string.sub(string.lower(label), 1, 9) == "ff_titan:")
end

local function ff_story_computer_self_clean()
  for _, path in ipairs({"startup", "startup.lua"}) do
    if fs.exists(path) and not fs.isDir(path) then
      local handle = fs.open(path, "r")
      local first_line = nil
      if handle ~= nil then
        first_line = handle.readLine()
        handle.close()
      end
      if first_line == "-- FF_STORY_COMPUTER_GUARD" then
        fs.delete(path)
      end
    end
  end
end

if not ff_story_computer_allowed() then
  ff_story_computer_self_clean()
  return
end
local OUTPUT_SIDE = "back"
local STATE_FILE = ".red_reactor_containment_signal"

local answers = {
  "FLOOD",
  "SCRAM",
  "PURGE",
  "CLAMP"
}

local prompts = {
  {
    title = "COOLANT LOOP",
    question = "Two coolant loops are starved. Enter the required coolant action."
  },
  {
    title = "ROD BANK",
    question = "The scram bus is AMBER. Enter the rod-bank action."
  },
  {
    title = "GAS STACK",
    question = "The alarm bulb is missing. Enter the gas-stack action."
  },
  {
    title = "FIELD COILS",
    question = "Coil pair 4 is shaking. Enter the final containment action."
  }
}

local strikes = 0
local maxStrikes = 3

local function hasColor()
  return term.isColor and term.isColor()
end

local function c(col)
  if hasColor() then term.setTextColor(col) end
end

local function cls()
  term.setBackgroundColor(colors.black)
  term.clear()
  term.setCursorPos(1, 1)
end

local function writeLine(text, col)
  c(col or colors.white)
  print(text)
end

local function readClean()
  c(colors.white)
  write("> ")
  local s = read() or ""
  s = string.upper(s)
  s = string.gsub(s, "^%s+", "")
  s = string.gsub(s, "%s+$", "")
  return s
end

local function pause()
  c(colors.gray)
  print("")
  print("[key] back")
  os.pullEvent("key")
end

local function header(title)
  cls()
  c(colors.red)
  print("FUSION REACTOR CONTROL")
  c(colors.gray)
  print("RED LEVEL LOCAL TERMINAL")
  print("---------------------------------------")

  if title then
    c(colors.white)
    print(title)
    c(colors.gray)
    print("---------------------------------------")
  end

  c(colors.white)
end

local function active()
  return fs.exists(STATE_FILE)
end

local function saveActive()
  local f = fs.open(STATE_FILE, "w")
  f.write("REACTOR CONTAINMENT SIGNAL")
  f.close()
end

local function setOutput(on)
  redstone.setOutput(OUTPUT_SIDE, on)
end

local function bootOutput()
  setOutput(active())
end

local function lineColor(line)
  if line == "FLOOD" or line == "SCRAM" or line == "PURGE" or line == "CLAMP" then
    return colors.lime
  end

  if string.find(line, "STRIKE") or string.find(line, "INCORRECT") or string.find(line, "LOCKOUT") then
    return colors.red
  end

  if string.find(line, "RULE") or string.find(line, "IF ") or string.find(line, "THEN ") then
    return colors.orange
  end

  if string.find(line, "948") or string.find(line, "240") or string.find(line, "AMBER") or string.find(line, "BETA") then
    return colors.cyan
  end

  return colors.white
end

local function draw(lines)
  for _, line in ipairs(lines) do
    writeLine(line, lineColor(line))
  end
end

local function page(title, lines)
  header(title)
  draw(lines)
  pause()
end

local function status()
  if active() then
    page("STATUS", {
      "CONTAINMENT SIGNAL: ACTIVE",
      "",
      "Back output is ON.",
      "",
      "Reactor shutdown signal is armed."
    })
  else
    page("STATUS", {
      "CONTAINMENT SIGNAL: OFFLINE",
      "",
      "Shutdown sequence incomplete.",
      "",
      "Current strike count:",
      tostring(strikes) .. " / " .. tostring(maxStrikes)
    })
  end
end

local function incidentLog()
  page("INCIDENT LOG", {
    "T-14N RED LEVEL INCIDENT LOG",
    "",
    "Case plate:",
    "T-14N-RX-948-A",
    "",
    "Service date:",
    "17 / 04",
    "",
    "Loop plate:",
    "BETA",
    "",
    "Scram bus:",
    "AMBER",
    "",
    "Panel readings:",
    "Core temp: 948",
    "External pressure: 240 o",
    "",
    "Coolant loop A: starved",
    "Coolant loop B: stable",
    "Coolant loop C: starved",
    "",
    "Rod bank 1: stuck open",
    "Rod bank 2: moving",
    "Rod bank 3: moving",
    "",
    "Gas stack:",
    "sample tube clouded",
    "alarm bulb missing",
    "",
    "Field coils:",
    "coil pair 4 shaking",
    "",
    "Do not use remote database values.",
    "Use local readings only."
  })
end

local function reactorManual()
  page("REACTOR MANUAL", {
    "LOCAL SHUTDOWN RULES",
    "",
    "Use the FIRST matching rule.",
    "",
    "COOLANT LOOP RULES",
    "IF two loops are starved",
    "THEN FLOOD",
    "IF loop B is starved",
    "THEN ISOLATE",
    "IF serial ends in B",
    "THEN VENT",
    "OTHERWISE HOLD",
    "",
    "ROD BANK RULES",
    "IF scram bus is AMBER",
    "THEN SCRAM",
    "IF bank 1 is moving",
    "THEN BRAKE",
    "IF service date day is odd",
    "THEN LOCK",
    "OTHERWISE WAIT",
    "",
    "GAS STACK RULES",
    "IF alarm bulb is missing",
    "THEN PURGE",
    "IF external pressure is above 200",
    "THEN SEAL",
    "IF sample tube is clear",
    "THEN HOLD",
    "OTHERWISE VENT",
    "",
    "FIELD COIL RULES",
    "IF coil pair 4 is shaking",
    "THEN CLAMP",
    "IF serial contains RX",
    "THEN GROUND",
    "IF core temp is below 700",
    "THEN WAIT",
    "OTHERWISE TRIP",
    "",
    "Field coils are last.",
    "Do not clamp before gas purge."
  })
end

local function fail(label, got)
  strikes = strikes + 1

  page("INCORRECT", {
    "CHECK FAILED",
    "",
    "Field:",
    label,
    "",
    "Input:",
    got,
    "",
    "Result:",
    "INCORRECT",
    "",
    "Strike:",
    tostring(strikes) .. " / " .. tostring(maxStrikes),
    "",
    "Containment signal not armed."
  })
end

local function lockout()
  page("LOCKOUT", {
    "LOCAL LOCKOUT",
    "",
    "Too many strikes.",
    "",
    "Containment signal refused.",
    "",
    "Cycle terminal power to retry.",
    "",
    "If this is live:",
    "send someone else."
  })
end

local function ask(step, expected)
  header("SHUTDOWN / " .. step.title)

  draw({
    "Prompt:",
    step.question,
    "",
    "Enter one word.",
    ""
  })

  local got = readClean()

  if got == expected then
    c(colors.lime)
    print("")
    print("CORRECT")
    sleep(0.8)
    return true
  end

  c(colors.red)
  print("")
  print("INCORRECT")
  sleep(0.8)

  fail(step.title, got)
  return false
end

local function shutdown()
  if active() then
    page("REACTOR SHUTDOWN", {
      "Shutdown signal already armed.",
      "",
      "Back output remains ON."
    })
    return
  end

  if strikes >= maxStrikes then
    lockout()
    return
  end

  header("REACTOR SHUTDOWN")
  draw({
    "This sequence arms the local",
    "reactor containment signal.",
    "",
    "Read the incident log.",
    "Read the reactor manual.",
    "",
    "Wrong answers add strikes.",
    "Three strikes lock the terminal.",
    "",
    "Press any key to begin."
  })
  os.pullEvent("key")

  for i = 1, #prompts do
    if strikes >= maxStrikes then
      lockout()
      return
    end

    if not ask(prompts[i], answers[i]) then
      return
    end
  end

  saveActive()
  setOutput(true)

  page("SHUTDOWN ARMED", {
    "ALL CHECKS ACCEPTED",
    "",
    "Coolant loop: FLOOD",
    "Rod bank: SCRAM",
    "Gas stack: PURGE",
    "Field coils: CLAMP",
    "",
    "REACTOR CONTAINMENT SIGNAL",
    "ACTIVE",
    "",
    "Back output is now ON."
  })
end

bootOutput()

while true do
  header()

  if active() then
    writeLine("CONTAINMENT SIGNAL: ACTIVE", colors.lime)
  else
    writeLine("CONTAINMENT SIGNAL: OFFLINE", colors.red)
  end

  print("")
  writeLine("1. Incident log")
  writeLine("2. Reactor manual")
  writeLine("3. Reactor shutdown")
  writeLine("4. Status")
  writeLine("Q. Close")
  print("")

  local input = readClean()

  if input == "Q" or input == "QUIT" or input == "EXIT" then
    cls()
    writeLine("SESSION CLOSED", colors.gray)
    return
  elseif input == "1" then
    incidentLog()
  elseif input == "2" then
    reactorManual()
  elseif input == "3" then
    shutdown()
  elseif input == "4" then
    status()
  else
    c(colors.red)
    print("Invalid.")
    sleep(0.7)
  end
end