using System;
using System.Collections.Generic;
using Npgsql;
using PhoenixLib.Logging;
using WingsEmu.DTOs.Quests;

namespace Plugin.QuestImpl.Managers
{
public static class QuestPostgresSync
{
    private static bool Enabled => !string.Equals(Environment.GetEnvironmentVariable("PARSER_DB_SYNC"), "false", StringComparison.OrdinalIgnoreCase);

    private static string BuildConnectionString()
    {
        string host = Environment.GetEnvironmentVariable("DATABASE_IP")
                      ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_IP")
                      ?? "127.0.0.1";
        string port = Environment.GetEnvironmentVariable("DATABASE_PORT")
                      ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PORT")
                      ?? "5432";
        string db = Environment.GetEnvironmentVariable("DATABASE_NAME")
                    ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_NAME")
                    ?? "game";
        string user = Environment.GetEnvironmentVariable("DATABASE_USER")
                      ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_USER")
                      ?? "postgres";
        string pass = Environment.GetEnvironmentVariable("DATABASE_PASSWORD")
                      ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PASSWORD")
                      ?? "postgres";

        return $"Host={host};Port={port};Database={db};Username={user};Password={pass}";
    }

    public static void Sync(IReadOnlyList<QuestDto> quests, IReadOnlyList<TutorialDto> tutorials, IReadOnlyList<QuestNpcDto> questNpcs)
    {
        if (!Enabled) return;

        try
        {
            using var conn = new NpgsqlConnection(BuildConnectionString());
            conn.Open();
            using var tx = conn.BeginTransaction();

            using (var cmd = new NpgsqlCommand(@"
CREATE TABLE IF NOT EXISTS quests (
  id BIGSERIAL PRIMARY KEY,
  quest_id INT,
  name TEXT,
  description TEXT,
  auto_finish BOOLEAN,
  dialog_starting INT,
  dialog_finish INT,
  dialog_during INT,
  min_level INT,
  max_level INT,
  next_quest_id INT,
  quest_type INT,
  required_quest_id INT,
  talker_vnum INT,
  target_map_id INT,
  target_map_x INT,
  target_map_y INT,
  unknown1 INT,
  is_blue BOOLEAN
);
CREATE TABLE IF NOT EXISTS quest_objectives (
  id BIGSERIAL PRIMARY KEY,
  quest_id INT,
  data0 INT,
  data1 INT,
  data2 INT,
  data3 INT,
  objective_index INT
);
CREATE TABLE IF NOT EXISTS quest_prizes (
  id BIGSERIAL PRIMARY KEY,
  quest_id INT,
  reward_type INT,
  data0 INT,
  data1 INT,
  data2 INT,
  data3 INT,
  data4 INT
);
CREATE TABLE IF NOT EXISTS tutorials (
  id BIGSERIAL PRIMARY KEY,
  tutorial_id INT,
  data INT,
  script_id INT,
  script_index INT,
  type INT
);
CREATE TABLE IF NOT EXISTS quest_npcs (
  id BIGSERIAL PRIMARY KEY,
  quest_npc_id INT,
  quest_id INT,
  npc_vnum INT,
  level INT,
  starting_script INT,
  required_completed_script INT,
  is_main_quest BOOLEAN,
  map_id INT
);", conn, tx)) cmd.ExecuteNonQuery();

            using (var cmd = new NpgsqlCommand("TRUNCATE TABLE quests, quest_objectives, quest_prizes, tutorials, quest_npcs RESTART IDENTITY;", conn, tx)) cmd.ExecuteNonQuery();

            foreach (QuestDto q in quests)
            {
                using (var cmd = new NpgsqlCommand(@"INSERT INTO quests(quest_id,name,description,auto_finish,dialog_starting,dialog_finish,dialog_during,min_level,max_level,next_quest_id,quest_type,required_quest_id,talker_vnum,target_map_id,target_map_x,target_map_y,unknown1,is_blue)
VALUES (@id,@name,@desc,@auto,@ds,@df,@dd,@min,@max,@next,@qt,@req,@talk,@tmid,@tmx,@tmy,@u1,@blue);", conn, tx))
                {
                    cmd.Parameters.AddWithValue("id", q.Id);
                    cmd.Parameters.AddWithValue("name", (object?)q.Name ?? DBNull.Value);
                    cmd.Parameters.AddWithValue("desc", (object?)q.Description ?? DBNull.Value);
                    cmd.Parameters.AddWithValue("auto", q.AutoFinish);
                    cmd.Parameters.AddWithValue("ds", q.DialogStarting);
                    cmd.Parameters.AddWithValue("df", q.DialogFinish);
                    cmd.Parameters.AddWithValue("dd", q.DialogDuring);
                    cmd.Parameters.AddWithValue("min", q.MinLevel);
                    cmd.Parameters.AddWithValue("max", q.MaxLevel);
                    cmd.Parameters.AddWithValue("next", q.NextQuestId);
                    cmd.Parameters.AddWithValue("qt", (int)q.QuestType);
                    cmd.Parameters.AddWithValue("req", q.RequiredQuestId);
                    cmd.Parameters.AddWithValue("talk", q.TalkerVnum);
                    cmd.Parameters.AddWithValue("tmid", q.TargetMapId);
                    cmd.Parameters.AddWithValue("tmx", q.TargetMapX);
                    cmd.Parameters.AddWithValue("tmy", q.TargetMapY);
                    cmd.Parameters.AddWithValue("u1", q.Unknown1);
                    cmd.Parameters.AddWithValue("blue", q.IsBlue);
                    cmd.ExecuteNonQuery();
                }

                if (q.Objectives != null)
                {
                    foreach (QuestObjectiveDto o in q.Objectives)
                    {
                        using var cmd = new NpgsqlCommand(@"INSERT INTO quest_objectives(quest_id,data0,data1,data2,data3,objective_index)
VALUES (@qid,@d0,@d1,@d2,@d3,@idx);", conn, tx);
                        cmd.Parameters.AddWithValue("qid", q.Id);
                        cmd.Parameters.AddWithValue("d0", o.Data0);
                        cmd.Parameters.AddWithValue("d1", o.Data1);
                        cmd.Parameters.AddWithValue("d2", o.Data2);
                        cmd.Parameters.AddWithValue("d3", o.Data3);
                        cmd.Parameters.AddWithValue("idx", o.ObjectiveIndex);
                        cmd.ExecuteNonQuery();
                    }
                }

                if (q.Prizes != null)
                {
                    foreach (QuestPrizeDto p in q.Prizes)
                    {
                        using var cmd = new NpgsqlCommand(@"INSERT INTO quest_prizes(quest_id,reward_type,data0,data1,data2,data3,data4)
VALUES (@qid,@rt,@d0,@d1,@d2,@d3,@d4);", conn, tx);
                        cmd.Parameters.AddWithValue("qid", q.Id);
                        cmd.Parameters.AddWithValue("rt", p.RewardType);
                        cmd.Parameters.AddWithValue("d0", p.Data0);
                        cmd.Parameters.AddWithValue("d1", p.Data1);
                        cmd.Parameters.AddWithValue("d2", p.Data2);
                        cmd.Parameters.AddWithValue("d3", p.Data3);
                        cmd.Parameters.AddWithValue("d4", p.Data4);
                        cmd.ExecuteNonQuery();
                    }
                }
            }

            foreach (TutorialDto t in tutorials)
            {
                using var cmd = new NpgsqlCommand("INSERT INTO tutorials(tutorial_id,data,script_id,script_index,type) VALUES (@id,@data,@sid,@sidx,@type);", conn, tx);
                cmd.Parameters.AddWithValue("id", t.Id);
                cmd.Parameters.AddWithValue("data", t.Data);
                cmd.Parameters.AddWithValue("sid", t.ScriptId);
                cmd.Parameters.AddWithValue("sidx", t.ScriptIndex);
                cmd.Parameters.AddWithValue("type", (int)t.Type);
                cmd.ExecuteNonQuery();
            }

            foreach (QuestNpcDto n in questNpcs)
            {
                using var cmd = new NpgsqlCommand(@"INSERT INTO quest_npcs(quest_npc_id,quest_id,npc_vnum,level,starting_script,required_completed_script,is_main_quest,map_id)
VALUES (@id,@qid,@npc,@lvl,@start,@req,@main,@map);", conn, tx);
                cmd.Parameters.AddWithValue("id", n.Id);
                cmd.Parameters.AddWithValue("qid", (object?)n.QuestId ?? DBNull.Value);
                cmd.Parameters.AddWithValue("npc", n.NpcVnum);
                cmd.Parameters.AddWithValue("lvl", n.Level);
                cmd.Parameters.AddWithValue("start", n.StartingScript);
                cmd.Parameters.AddWithValue("req", n.RequiredCompletedScript);
                cmd.Parameters.AddWithValue("main", n.IsMainQuest);
                cmd.Parameters.AddWithValue("map", n.MapId);
                cmd.ExecuteNonQuery();
            }

            tx.Commit();
            Log.Info($"[PARSER_DB_SYNC] Synced quests={quests.Count} tutorials={tutorials.Count} quest_npcs={questNpcs.Count}");
        }
        catch (Exception ex)
        {
            Log.Error("[PARSER_DB_SYNC] Failed to sync quests", ex);
        }
    }
}
}

