using Sunfish.Auth;
using Sunfish.Config;
using Sunfish.Net;

namespace Sunfish.Cli;

/// <summary>
/// sunfish-cli admin status|enable|disable|passwd|allow LISTA: panel de administracion web.
/// sunfish-cli import-v2 [FICHERO]: importa la configuracion de Sunfish 2.0.
/// </summary>
internal static class AdminCommands
{
    public static int RunAdmin(string[] args)
    {
        var (configPath, rest) = CommonOptions(args);
        if (rest.Count == 0)
        {
            Console.Error.WriteLine(Texts.AdminUsage);
            return 1;
        }
        string path = ConfigLocator.Find(configPath) ?? ConfigLocator.PortablePath;
        var config = File.Exists(path) ? SunfishConfig.Load(path) : new SunfishConfig { FilePath = path };
        var admin = config.Admin;

        switch (rest[0])
        {
            case "status" when rest.Count == 1:
                Console.WriteLine(admin.Enabled && admin.PasswordHash.Length > 0 ? Texts.AdminOn : Texts.AdminOffText);
                Console.WriteLine(Texts.AdminAllowed(string.Join(", ", admin.AllowFrom)));
                if (admin.Enabled)
                    Console.WriteLine(Strings.AdminUrl($"http://127.0.0.1:{config.Server.HttpPort}/$sunfish/admin/"));
                return 0;

            case "enable" when rest.Count == 1:
                if (admin.PasswordHash.Length == 0)
                {
                    Console.Error.WriteLine(Texts.AdminNeedsPassword);
                    if (UserCommands.AskNewPassword() is not { } first)
                        return 1;
                    admin.PasswordHash = Passwords.Hash(first);
                }
                admin.Enabled = true;
                config.Save(path);
                Console.WriteLine(Strings.AdminUrl($"http://127.0.0.1:{config.Server.HttpPort}/$sunfish/admin/") + "  (" + WebUser + ")");
                return 0;

            case "disable" when rest.Count == 1:
                admin.Enabled = false;
                config.Save(path);
                Console.WriteLine(Texts.AdminOffText);
                return 0;

            case "passwd" when rest.Count == 1:
                if (UserCommands.AskNewPassword() is not { } password)
                    return 1;
                admin.PasswordHash = Passwords.Hash(password);
                config.Save(path);
                Console.WriteLine(Texts.AdminPasswordSaved(path));
                return 0;

            case "allow" when rest.Count > 1:
                var rules = string.Join(' ', rest.Skip(1)).Split([',', ' ', ';'], StringSplitOptions.RemoveEmptyEntries).ToList();
                if (rules.FirstOrDefault(r => !AddressRules.IsValid(r)) is { } bad)
                {
                    Console.Error.WriteLine(Strings.AdminBadAllow(bad));
                    return 1;
                }
                admin.AllowFrom = rules;
                config.Save(path);
                Console.WriteLine(Texts.AdminAllowed(string.Join(", ", rules)));
                return 0;

            default:
                Console.Error.WriteLine(Texts.AdminUsage);
                return 1;
        }
    }

    private static string WebUser => Strings.Spanish ? "usuario: admin" : "user: admin";

    public static int RunImport(string[] args)
    {
        var (configPath, rest) = CommonOptions(args);
        string? source = rest.Count > 0 ? rest[0] : LegacyImport.Find();
        if (source is null || !File.Exists(source))
        {
            Console.Error.WriteLine(Texts.ImportNotFound(LegacyImport.FileName));
            return 1;
        }
        string? found = ConfigLocator.Find(configPath);
        bool isNew = found is null || !File.Exists(found);
        string path = found ?? configPath ?? ConfigLocator.PortablePath;
        return Import(source, path, isNew) ? 0 : 1;
    }

    /// <summary>Importa <paramref name="source"/> en la configuracion de <paramref name="path"/> y lo explica.</summary>
    public static bool Import(string source, string path, bool isNew)
    {
        var notes = new List<string>();
        var imported = LegacyImport.FromV2(File.ReadAllText(source), notes);
        if (imported is null)
        {
            Console.Error.WriteLine(Strings.ImportInvalid(source));
            return false;
        }
        var config = isNew ? new SunfishConfig() : SunfishConfig.Load(path);
        int count = LegacyImport.Merge(config, imported, isNew);
        config.Save(path);
        Console.WriteLine(Strings.ImportDone(count, path));
        foreach (var note in notes)
            Console.WriteLine("  - " + note);
        return true;
    }

    private static (string? ConfigPath, List<string> Args) CommonOptions(string[] args)
    {
        string? configPath = null;
        var rest = new List<string>();
        for (int i = 0; i < args.Length; i++)
        {
            if (args[i] is "-c" or "--config" && i + 1 < args.Length)
                configPath = args[++i];
            else if (args[i] == "--lang" && i + 1 < args.Length)
                Strings.Force(args[++i]);
            else
                rest.Add(args[i]);
        }
        return (configPath, rest);
    }
}
