param(
    [string]$DbContainer = "wingsemu-postgres",
    [string]$DbName = "game",
    [string]$DbUser = "postgres",
    [string]$ConfigRoot = "config"
)

$ErrorActionPreference = 'Stop'

$root = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path))
Set-Location $root

$configPath = Join-Path $root $ConfigRoot
if (-not (Test-Path $configPath)) { throw "Config path not found: $configPath" }

$maps = @()
$mapFlags = @()
$portals = @()
$npcs = @()
$monsters = @()

function To-IntOrNull($v) {
    if ([string]::IsNullOrWhiteSpace($v)) { return $null }
    $v = ($v -split '#')[0].Trim()
    if ($v -match '^-?\d+$') { return [int]$v }
    return $null
}

function SqlEsc([string]$s) {
    if ($null -eq $s) { return 'NULL' }
    return "'" + ($s -replace "'","''") + "'"
}

function SqlNum($n) {
    if ($null -eq $n) { return 'NULL' }
    return [string]$n
}

function Read-NonCommentLines([string]$file) {
    Get-Content $file | ForEach-Object { $_.TrimEnd() } | Where-Object { $_ -notmatch '^\s*#' }
}

# -------- maps --------
Get-ChildItem (Join-Path $configPath 'maps') -File -ErrorAction SilentlyContinue | ForEach-Object {
    $lines = Read-NonCommentLines $_.FullName
    $current = $null
    $inFlags = $false

    foreach ($line in $lines) {
        if ($line -match '^\s*-\s*map_id\s*:\s*(.+)$') {
            if ($current) { $maps += $current }
            $current = [ordered]@{ map_id = To-IntOrNull $matches[1]; map_vnum = $null; map_name_id = $null; map_music_id = $null; flags = @() }
            $inFlags = $false
            continue
        }
        if (-not $current) { continue }

        if ($line -match '^\s*flags\s*:') { $inFlags = $true; continue }

        if ($inFlags -and $line -match '^\s*-\s*([A-Z0-9_]+)\s*$') {
            $current.flags += $matches[1]
            continue
        }

        if ($line -match '^\s*map_vnum\s*:\s*(.+)$') { $current.map_vnum = To-IntOrNull $matches[1]; $inFlags=$false; continue }
        if ($line -match '^\s*map_name_id\s*:\s*(.+)$') { $current.map_name_id = To-IntOrNull $matches[1]; $inFlags=$false; continue }
        if ($line -match '^\s*map_music_id\s*:\s*(.+)$') { $current.map_music_id = To-IntOrNull $matches[1]; $inFlags=$false; continue }
    }

    if ($current) { $maps += $current }
}

foreach ($m in $maps) {
    foreach ($f in $m.flags) {
        $mapFlags += [ordered]@{ map_id = $m.map_id; flag = $f }
    }
}

# -------- portals --------
Get-ChildItem (Join-Path $configPath 'map_portals') -File -ErrorAction SilentlyContinue | ForEach-Object {
    $lines = Read-NonCommentLines $_.FullName
    $current = $null
    foreach ($line in $lines) {
        if ($line -match '^\s*-\s*destination_map_id\s*:\s*(.+)$') {
            if ($current) { $portals += $current }
            $current = [ordered]@{
                destination_map_id = To-IntOrNull $matches[1]
                destination_map_x = $null
                destination_map_y = $null
                source_map_id = $null
                source_map_x = $null
                source_map_y = $null
                type = $null
            }
            continue
        }
        if (-not $current) { continue }
        if ($line -match '^\s*destination_map_x\s*:\s*(.+)$') { $current.destination_map_x = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*destination_map_y\s*:\s*(.+)$') { $current.destination_map_y = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*source_map_id\s*:\s*(.+)$') { $current.source_map_id = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*source_map_x\s*:\s*(.+)$') { $current.source_map_x = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*source_map_y\s*:\s*(.+)$') { $current.source_map_y = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*type\s*:\s*(.+)$') { $current.type = To-IntOrNull $matches[1]; continue }
    }
    if ($current) { $portals += $current }
}

# -------- npcs --------
Get-ChildItem (Join-Path $configPath 'map_npc_placement') -File -ErrorAction SilentlyContinue | ForEach-Object {
    $lines = Read-NonCommentLines $_.FullName
    $mapId = $null
    $current = $null
    foreach ($line in $lines) {
        if ($line -match '^\s*map_id\s*:\s*(.+)$') { $mapId = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*-\s*map_npc_id\s*:\s*(.+)$') {
            if ($current) { $npcs += $current }
            $current = [ordered]@{ map_id=$mapId; map_npc_id=To-IntOrNull $matches[1]; vnum=$null; pos_x=$null; pos_y=$null; effect_vnum=$null; effect_delay=$null; dialog_id=$null; direction_facing=$null }
            continue
        }
        if (-not $current) { continue }
        if ($line -match '^\s*vnum\s*:\s*(.+)$') { $current.vnum = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*pos_x\s*:\s*(.+)$') { $current.pos_x = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*pos_y\s*:\s*(.+)$') { $current.pos_y = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*effect_vnum\s*:\s*(.+)$') { $current.effect_vnum = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*effect_delay\s*:\s*(.+)$') { $current.effect_delay = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*dialog_id\s*:\s*(.+)$') { $current.dialog_id = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*direction_facing\s*:\s*(.+)$') { $current.direction_facing = To-IntOrNull $matches[1]; continue }
    }
    if ($current) { $npcs += $current }
}

# -------- monsters --------
Get-ChildItem (Join-Path $configPath 'map_monster_placement') -File -ErrorAction SilentlyContinue | ForEach-Object {
    $lines = Read-NonCommentLines $_.FullName
    $mapId = $null
    $current = $null
    foreach ($line in $lines) {
        if ($line -match '^\s*map_id\s*:\s*(.+)$') { $mapId = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*-\s*map_monster_id\s*:\s*(.+)$') {
            if ($current) { $monsters += $current }
            $current = [ordered]@{ map_id=$mapId; map_monster_id=To-IntOrNull $matches[1]; vnum=$null; map_x=$null; map_y=$null; position=$null; can_move=$null }
            continue
        }
        if (-not $current) { continue }
        if ($line -match '^\s*vnum\s*:\s*(.+)$') { $current.vnum = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*map_x\s*:\s*(.+)$') { $current.map_x = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*map_y\s*:\s*(.+)$') { $current.map_y = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*position\s*:\s*(.+)$') { $current.position = To-IntOrNull $matches[1]; continue }
        if ($line -match '^\s*can_move\s*:\s*(.+)$') { $current.can_move = ($matches[1].Trim().ToLower() -eq 'true'); continue }
    }
    if ($current) { $monsters += $current }
}

$sql = New-Object System.Text.StringBuilder
[void]$sql.AppendLine("BEGIN;")
[void]$sql.AppendLine(@"
DROP TABLE IF EXISTS server_map_flags;
DROP TABLE IF EXISTS server_maps;
DROP TABLE IF EXISTS map_portals;
DROP TABLE IF EXISTS map_npcs;
DROP TABLE IF EXISTS map_monsters;

CREATE TABLE server_maps (
  map_id INT PRIMARY KEY,
  map_vnum INT,
  map_name_id INT,
  map_music_id INT
);
CREATE TABLE server_map_flags (
  map_id INT NOT NULL,
  flag TEXT NOT NULL,
  PRIMARY KEY (map_id, flag)
);
CREATE TABLE map_portals (
  id BIGSERIAL PRIMARY KEY,
  destination_map_id INT,
  destination_map_x INT,
  destination_map_y INT,
  source_map_id INT,
  source_map_x INT,
  source_map_y INT,
  type INT
);
CREATE TABLE map_npcs (
  id BIGSERIAL PRIMARY KEY,
  map_npc_id INT,
  map_id INT,
  vnum INT,
  pos_x INT,
  pos_y INT,
  effect_vnum INT,
  effect_delay INT,
  dialog_id INT,
  direction_facing INT
);
CREATE TABLE map_monsters (
  id BIGSERIAL PRIMARY KEY,
  map_monster_id INT,
  map_id INT,
  vnum INT,
  map_x INT,
  map_y INT,
  position INT,
  can_move BOOLEAN
);
"@)

foreach ($m in $maps | Where-Object { $null -ne $_.map_id }) {
    [void]$sql.AppendLine("INSERT INTO server_maps(map_id,map_vnum,map_name_id,map_music_id) VALUES ($(SqlNum $m.map_id),$(SqlNum $m.map_vnum),$(SqlNum $m.map_name_id),$(SqlNum $m.map_music_id));")
}
foreach ($f in $mapFlags | Where-Object { $null -ne $_.map_id -and -not [string]::IsNullOrWhiteSpace($_.flag) }) {
    [void]$sql.AppendLine("INSERT INTO server_map_flags(map_id,flag) VALUES ($(SqlNum $f.map_id),$(SqlEsc $f.flag));")
}
foreach ($p in $portals) {
    [void]$sql.AppendLine("INSERT INTO map_portals(destination_map_id,destination_map_x,destination_map_y,source_map_id,source_map_x,source_map_y,type) VALUES ($(SqlNum $p.destination_map_id),$(SqlNum $p.destination_map_x),$(SqlNum $p.destination_map_y),$(SqlNum $p.source_map_id),$(SqlNum $p.source_map_x),$(SqlNum $p.source_map_y),$(SqlNum $p.type));")
}
foreach ($n in $npcs | Where-Object { $null -ne $_.map_npc_id }) {
    [void]$sql.AppendLine("INSERT INTO map_npcs(map_npc_id,map_id,vnum,pos_x,pos_y,effect_vnum,effect_delay,dialog_id,direction_facing) VALUES ($(SqlNum $n.map_npc_id),$(SqlNum $n.map_id),$(SqlNum $n.vnum),$(SqlNum $n.pos_x),$(SqlNum $n.pos_y),$(SqlNum $n.effect_vnum),$(SqlNum $n.effect_delay),$(SqlNum $n.dialog_id),$(SqlNum $n.direction_facing));")
}
foreach ($m in $monsters | Where-Object { $null -ne $_.map_monster_id }) {
    $mv = if ($null -eq $m.can_move) { 'NULL' } elseif ($m.can_move) { 'TRUE' } else { 'FALSE' }
    [void]$sql.AppendLine("INSERT INTO map_monsters(map_monster_id,map_id,vnum,map_x,map_y,position,can_move) VALUES ($(SqlNum $m.map_monster_id),$(SqlNum $m.map_id),$(SqlNum $m.vnum),$(SqlNum $m.map_x),$(SqlNum $m.map_y),$(SqlNum $m.position),$mv);")
}

[void]$sql.AppendLine("COMMIT;")

$tmpSql = Join-Path $env:TEMP "parser_import.sql"
[System.IO.File]::WriteAllText($tmpSql, $sql.ToString())

Get-Content -Raw $tmpSql | docker exec -i $DbContainer psql -v ON_ERROR_STOP=1 -U $DbUser -d $DbName | Out-Host

Write-Host "Imported maps=$($maps.Count) flags=$($mapFlags.Count) portals=$($portals.Count) npcs=$($npcs.Count) monsters=$($monsters.Count)" -ForegroundColor Green
