using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Extensions.Configuration;

namespace Elwig.Helpers {

    public enum WeighingMode { Gross, Net, Box }

    public record struct ScaleConfig {
        public string Id;
        public string? Type;
        public string? Model;
        public string? Connection;
        public string? Empty;
        public string? Filling;
        public string? Limit;
        public bool Required;
        public string? Log;
        public string? _Log;

        public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
            Id = id;
            Type = type;
            Model = model;
            Connection = cnx;
            Empty = empty;
            Filling = filling;
            Limit = limit;
            Required = required ?? true;
            _Log = log;
            Log = log != null ? Path.Combine(App.DataPath, log) : null;
        }
    }

    public class Config {

        private static readonly string[] TrueValues = ["1", "true", "yes", "on"];

        private readonly string FileName;

        public bool Debug;
        public string DatabaseFile = App.DataPath + "database.sqlite3";
        public string? DatabaseLog = null;
        public string? Branch = null;
        public WeighingMode? WeighingMode;
        public string? UpdateUrl = null;
        public bool UpdateAuto = false;
        public string? SyncUrl = null;
        public string SyncUsername = "";
        public string SyncPassword = "";

        public string? SmtpHost = null;
        public int? SmtpPort = null;
        public string? SmtpMode = null;
        public string? SmtpUsername = null;
        public string? SmtpPassword = null;
        public string? SmtpFrom = null;
        public (string Host, int Port, string Mode, string Username, string Password, string From)? Smtp =>
            SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
            null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom);

        public IList<ScaleConfig> Scales;
        private readonly List<ScaleConfig> ScaleList = [];

        public Config(string filename) {
            FileName = filename;
            Scales = ScaleList;
            Read();
        }

        public void Read() {
            var config = new ConfigurationBuilder().AddIniFile(FileName).Build();

            DatabaseFile = Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, config["database:file"] ?? "database.sqlite3");
            var log = config["database:log"];
            DatabaseLog = log != null ? Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, log) : null;
            Branch = config["general:branch"];
            Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
            var weighing = config["general:weighing"];
            WeighingMode = weighing != null && Enum.TryParse<WeighingMode>(weighing, true, out var w) ? w : null;
            UpdateUrl = config["update:url"];
            UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower());
            SyncUrl = config["sync:url"];
            SyncUsername = config["sync:username"] ?? "";
            SyncPassword = config["sync:password"] ?? "";

            SmtpHost = config["smtp:host"];
            SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
            SmtpMode = config["smtp:mode"];
            SmtpUsername = config["smtp:username"];
            SmtpPassword = config["smtp:password"];
            SmtpFrom = config["smtp:from"];

            var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
            ScaleList.Clear();
            Scales = ScaleList;
            foreach (var s in scales) {
                ScaleList.Add(new(
                    s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
                    config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
                    config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
                    config[$"scale.{s}:log"]
                ));
            }
        }
    }
}
