require "story"
local setups = require "ghost-rails"
required_count = 10
through_wall_path = 40

local no_deconstruction_markers = function()
  local all_ents = game.surfaces[1].find_entities()
  for _, entity in pairs(all_ents) do
    if entity.to_be_deconstructed() then return false end
  end
  return true
end

local reset_deconstruction = function()
  local all_ents = game.surfaces[1].find_entities()
  for _, entity in pairs(all_ents) do
    if entity.to_be_deconstructed() then entity.cancel_deconstruction('player') end
  end
end

local remove_all_rail_ghosts = function()
  local rail_ghosts = game.surfaces[1].find_entities_filtered({ghost_name={'straight-rail','curved-rail'}})
  for _, ghost in pairs(rail_ghosts) do
    ghost.destroy()
  end
end

local set_continue_button_state = function(state)
  set_continue_button_style(function (button)
    if button.valid then
      button.enabled = state
    end
  end)
  global.completed = state
end

function on_player_created(event)
  local player = game.players[event.player_index]
  player.game_view_settings =
  {
    show_side_menu = false,
    show_research_info = false,
    show_alert_gui = false,
    show_minimap = false
  }
  game.permissions.get_group(0).set_allows_action(defines.input_action.remove_cables, false)
  game.permissions.get_group(0).set_allows_action(defines.input_action.open_production_gui, false)
  game.permissions.get_group(0).set_allows_action(defines.input_action.open_tutorials_gui, false)
  game.permissions.get_group(0).set_allows_action(defines.input_action.open_logistic_gui, false)
  game.permissions.get_group(0).set_allows_action(defines.input_action.open_technology_gui, false)
  player.force.disable_all_prototypes()
end

intermission =
{
  init = function()
    player().clean_cursor()
    flying_congrats(global.last_built_position)
    set_goal()
    set_info()
  end,
  condition = story_elapsed_check(1)
}

story_table =
{
  {
    {condition = story_elapsed_check(1)},
    {
      init = function()
        global.built_rail = 0
        set_goal({"place-ghost-rail", global.built_rail, 4})
        set_info({text = {"place-ghost-rail-info"}})
        player().insert{name = "rail", count = 1000}
        player().set_quick_bar_slot(1,'rail')
      end,
      update = function(event)
        set_goal({"place-ghost-rail", surface().count_entities_filtered{name = "entity-ghost"}, 4}, true)
      end,
      condition = function(event)
        if event.name == defines.events.on_tick then
          return surface().count_entities_filtered{name = "entity-ghost"} >= 4
        end
      end,
      action = function()
      end
    },
    intermission,
    {
      init = function()
        set_goal({"start-ghost-rail-planning", 0, required_count})
        set_info(
        {
          text = {"start-ghost-rail-planning-info"},
          pictures =
          {
            "file/ghost-plan-1.png",
            "file/ghost-plan-2.png",
            {path = "file/ghost-plan-3.png", split = true}
          }
        })
        global.initial = surface().count_entities_filtered{type = "entity-ghost"}
      end,
      condition = function(event)
        if event.name == defines.events.on_tick then
          local count = 0
          for k, entity in pairs (surface().find_entities_filtered{type = "entity-ghost"}) do
            if entity.ghost_name == "curved-rail" then
              count = count + 1
            end
          end
          local count = count - global.initial
          set_goal({"start-ghost-rail-planning", math.max(count, 0), required_count}, true)
          return  count >= required_count
        end
      end,
      action = function()
        player().clean_cursor()
      end
    },
    intermission,
    {
      init = function()
        deconstruct_on_tick(surface().find_entities_filtered{name = "entity-ghost"})
      end,
      condition = function()
        return deconstruct_on_tick()
      end
    },
    {
      init = function()
        set_goal({"rotate-rail"})
        set_info({text = {"rotate-rail-info"}, picture = "file/rotate-rail.png"})
        local surface = surface()
        for k, v in pairs (surface.find_entities_filtered{name = "entity-ghost"}) do
          v.destroy()
        end
        surface.create_entity
        {
          name = "entity-ghost",
          inner_name = "straight-rail",
          direction = 2,
          position = {-7, -3},
          force = "player",
          expires = false
        }.minable = false
        surface.create_entity
        {
          name = "entity-ghost",
          inner_name = "straight-rail",
          direction = 2,
          position = {9,3},
          force = "player",
          expires = false
        }.minable = false
      end,
      condition = function(event)
        if event.name ~= defines.events.on_tick then return end
        local rails =
        {
          {position = {-2, -2}, area = {{-3, -3}, {-1,-1}}, direction = 3},
          {position = {4, 2}, area = {{5, 1}, {3, 3}}, direction = 7}
        }
        local surface = surface()
        count = 0
        for k, ghost in pairs (surface.find_entities_filtered({name = "entity-ghost"})) do
          for j, rail in pairs (rails) do
            if ghost.ghost_name == "curved-rail" and
               ghost.position.x == rail.position[1] and
               ghost.position.y == rail.position[2] and
               ghost.direction == rail.direction then
              count = count + 1
              break
            end
          end
        end
        if count >= 2 then
          return true
        end
        local any_destroyed = false
        for k, rail in pairs (surface.find_entities_filtered({name = "entity-ghost"})) do
          if rail.name ~= "character" and rail.minable then
            rail.destroy()
            any_destroyed = true
          end
        end
        if any_destroyed then
          game.print({"rotate-rail-not-1-tick"})
          player().clean_cursor()
        end
      end
    },
    intermission,
    {
      init = function()
        deconstruct_on_tick(surface().find_entities_filtered{name = "entity-ghost"})
      end,
      condition = function()
        return deconstruct_on_tick()
      end
    },
    {
      init = function() recreate_entities_on_tick(setups.plan_through_trees, nil, 1) end,
      condition = function() return recreate_entities_on_tick() end
    },
    {
      init = function()
        set_goal()
        set_info({text={"trace-path"}})
        set_info({text={"automatic-deconstruction"},append = true})
        set_info{custom_function = function(flow) add_button(flow).caption = {"continue"} end, append = true}
        set_continue_button_state(false)
        local surface = surface()
        global.text =
        {
          surface.create_entity{name = "tutorial-flying-text", text = {"connect-start"}, position = {-15, -12}},
          surface.create_entity{name = "tutorial-flying-text", text = {"connect-end"}, position = {-15, 10}}
        }
        for k, text in pairs (global.text) do
          text.active = false
        end
      end,
      update = function()
        local surface = surface()
        local count = 0
        for k, entity in pairs (setups.rails) do
          local ghost = surface.find_entity("entity-ghost", entity.position)
          if ghost then
            count = count + 1
          else
            local area = {{entity.position.x-2, entity.position.y-2}, {entity.position.x+2, entity.position.y+2}}
            for j, ghost in pairs (surface.find_entities_filtered{area = area, name = "entity-ghost"}) do
              if ((ghost.position.x == entity.position.x) and (ghost.position.y == entity.position.y) and (ghost.ghost_name == entity.name)) then
                count = count + 1
                break
              end
            end
          end
        end
        if count >= #setups.rails then
          set_continue_button_state(true)
        end
      end,
      condition = function() return global.continue end,
      action = function()
        for k, arrow in pairs (global.text) do
          if arrow.valid then
            arrow.destroy()
          end
        end
        global.arrows = nil
        player().clean_cursor()
        global.continue = false
      end
    },
    intermission,
    {
      init = function()
        local entities = {}
        for k, entity in pairs (surface().find_entities()) do
          if entity.name ~= "character" then
            entities[k] = entity
          end
        end
        deconstruct_on_tick(entities)
      end,
      condition = function()
        return deconstruct_on_tick()
      end
    },
    {
      init = function()
        local entities = {}
        local rand = math.random
        local list = {}
        for k, entity in pairs (setups.trees) do
          entity.force = "neutral"
          entity.minable = true
          table.insert(entities,entity)
        end
        --for k, entity in pairs (game.entity_prototypes) do
        --  if entity.type == "tree" then
        --    table.insert(list, entity.name)
        --  end
        --end
        --for k = 1, 350 do
        --  local position = {x = rand(-52,51), y = rand(-51,52)}
        --  entities[k] = {name = list[rand(#list)], position = position, force = "neutral", minable = true}
        --end
        entities[351] = {name = 'assembling-machine-1', position = {x=0,y=-10}, force = "neutral", minable = false}
        recreate_entities_on_tick(entities, {check_can_place = true}, 1)
        print(serpent.block(export_entities()))
      end,
      condition = function()
        return recreate_entities_on_tick()
      end
    },
    {
      init = function()
        set_goal({"crazy-rail", surface().count_entities_filtered{area = {{-50, -50}, {50, 50}}, name = "entity-ghost"}, through_wall_path})
        set_info({text = {"crazy-rail-info"}})
        set_info({custom_function = function(flow) add_button(flow).caption = {"reset"} end, append = true})
        player().insert({name='rail',count=1})
        local surface = surface()
        surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {-59, -9}, force = "player", expires = false}
        surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {59, -9}, force = "player", expires = false}
      end,
      update = function(event)
        if global.continue then
          remove_all_rail_ghosts()
          reset_deconstruction()
          local surface = surface()
          surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {-59, -9}, force = "player", expires = false}
          surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {59, -9}, force = "player", expires = false}
          global.continue = false
          set_continue_button_state(true)
        end
      end,
      condition = function(event)
        local count = surface().count_entities_filtered{name = "entity-ghost"}
        set_goal({"crazy-rail", count, through_wall_path}, true)
        return count >= through_wall_path
      end,
      
    },
    intermission,
    {
      init = function()
        remove_all_rail_ghosts()
        reset_deconstruction()
        set_goal({"crazy-rail-no-tree-loss", surface().count_entities_filtered{area = {{-50, -50}, {50, 50}}, name = "entity-ghost"}, through_wall_path})
        set_info({text = {"crazy-rail-no-tree-loss-info"}})
        set_info({custom_function = function(flow) add_button(flow).caption = {"reset"} end, append = true})
        local surface = surface()
        surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {-59, -9}, force = "player", expires = false}
        surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {59, -9}, force = "player", expires = false}
      end,
      update = function(event)
        if global.continue then
          remove_all_rail_ghosts()
          reset_deconstruction()
          local surface = surface()
          surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {-59, -9}, force = "player", expires = false}
          surface.create_entity{name = "entity-ghost", inner_name = "straight-rail", direction = 2, position = {59, -9}, force = "player", expires = false}
          global.continue = false
          set_continue_button_state(true)
        end
      end,
      condition = function(event)
        local count = surface().count_entities_filtered{name = "entity-ghost"}
        set_goal({"crazy-rail-no-tree-loss", count, through_wall_path}, true)
        local no_markers = no_deconstruction_markers()
        return count >= through_wall_path and no_markers
      end,
    },
    intermission,
    {
      init = function()
        set_info{text = {"finish-info"}}
        set_info{custom_function = function(flow) add_button(flow).caption = {"finish"} end, append = true}
        set_goal(nil, false)
      end,
      condition = function()
        return global.continue
      end

    }
  }
}

story_init_helpers(story_table)

script.on_init(function()
  game.forces.player.manual_mining_speed_modifier = 4
  game.forces.player.disable_all_prototypes()
  surface().always_day = true
  global.story = story_init()
end)

script.on_event(defines.events, function(event)
  check_built_real_rail(event)
  story_update(global.story, event, "")
  if event.name == defines.events.on_player_created then
    on_player_created(event)
  end
end)

function check_built_real_rail(event)
  if event.name ~= defines.events.on_tick then return end
  local surface = surface()
  local player = player()
  local create = false
  for k, rail in pairs (surface.find_entities_filtered{type = "straight-rail"}) do
    if rail.minable then
      rail.destroy()
      player.clean_cursor()
      player.insert{name = "rail", count = 1}
      create = true
    end
  end
  for k, rail in pairs (surface.find_entities_filtered{type = "curved-rail"}) do
    if rail.minable then
      rail.destroy()
      player.clean_cursor()
      player.insert{name = "rail", count = 4}
      create = true
    end
  end
  if create then
    surface.create_entity{
      name = "tutorial-flying-text",
      position = {player.position.x, player.position.y - 2},
      text = {"built-real-rail"},
      color = {r = 1, g = 0.1, b = 0.1}
    }
  end
end

function current_ghosts_count(area)
  if area then
    return surface().count_entities_filtered{area = area, name = "entity-ghost"}
  else
    return surface().count_entities_filtered{name = "entity-ghost"}
  end
end
