using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using PhoenixLib.Logging;
using WingsAPI.Data.GameData;
using WingsEmu.DTOs.Quests;

namespace Plugin.ResourceLoader.Loaders
{
    public class NpcQuestResourceFileLoader : IResourceLoader<QuestNpcDto>
    {
        private readonly ResourceLoadingConfiguration _configuration;

        public NpcQuestResourceFileLoader(ResourceLoadingConfiguration configuration) => _configuration = configuration;

        public async Task<IReadOnlyList<QuestNpcDto>> LoadAsync()
        {
            string filePath = Path.Combine(_configuration.GameDataPath, "qstnpc.dat");

            if (!File.Exists(filePath))
            {
                bool dbFirst = string.Equals(Environment.GetEnvironmentVariable("DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase)
                               || string.Equals(Environment.GetEnvironmentVariable("RESOURCE_DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase);
                if (dbFirst)
                {
                    TryHydrateDatFileFromDatabase("qstnpc.dat", filePath);
                }
            }

            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException($"{filePath} should be present");
            }

            var npcQuests = new List<QuestNpcDto>();
            using var idStream = new StreamReader(filePath, Encoding.GetEncoding(1252));
            string line;
            int counter = 0;
            int idCounter = 1;

            while ((line = idStream.ReadLine()) != null)
            {
                string[] currentLine = line.Split(' ');

                if (currentLine.Length < 5 || line.StartsWith('#'))
                {
                    continue;
                }

                counter++;
                var dto = new QuestNpcDto
                {
                    Id = idCounter++,
                    NpcVnum = short.Parse(currentLine[0]),
                    Level = short.Parse(currentLine[4])
                };

                bool isMainQuest = short.Parse(currentLine[1]) == 0;
                if (isMainQuest)
                {
                    dto.IsMainQuest = true;
                    dto.StartingScript = short.Parse(currentLine[2]);
                    dto.RequiredCompletedScript = short.Parse(currentLine[3]);
                    dto.MapId = short.Parse(currentLine[5]);
                }
                else
                {
                    dto.QuestId = int.Parse(currentLine[2]);
                    dto.IsMainQuest = false;
                }

                npcQuests.Add(dto);
            }

            Log.Info($"[RESOURCE_LOADER] {npcQuests.Count.ToString()} NPC quests loaded");
            return npcQuests;
        }

        private void TryHydrateDatFileFromDatabase(string datFileName, string targetPath)
        {
            try
            {
                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";

                using var conn = new NpgsqlConnection($"Host={host};Port={port};Database={db};Username={user};Password={pass}");
                conn.Open();

                using var cmd = new NpgsqlCommand("SELECT content FROM resource_files WHERE category='dat' AND relative_path=@path LIMIT 1;", conn);
                cmd.Parameters.AddWithValue("path", $"dat/{datFileName}");
                object result = cmd.ExecuteScalar();

                if (result is byte[] bytes && bytes.Length > 0)
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(targetPath) ?? _configuration.GameDataPath);
                    File.WriteAllBytes(targetPath, bytes);
                    Log.Info($"[DB_FIRST] Hydrated {datFileName} from resource_files");
                }
            }
            catch (Exception ex)
            {
                Log.Error($"[DB_FIRST] Could not hydrate {datFileName} from database", ex);
            }
        }
    }
}