using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using MySql.Data.MySqlClient;
using System.Text.Json;
using Aberwyn.Data;
using Aberwyn.Models;

namespace Aberwyn.Controllers
{
    [Route("setup")]
    public class SetupController : Controller
    {
        private readonly IWebHostEnvironment _env;
        private readonly ILogger<SetupController> _logger;

        public SetupController(IWebHostEnvironment env, ILogger<SetupController> logger)
        {
            _env = env;
            _logger = logger;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            ViewBag.IsSetupMode = true;
            base.OnActionExecuting(context);
        }

        [HttpGet]
        public IActionResult Index() => View(new SetupSettings());

        [Authorize(Roles = "Admin")]
        [HttpPost("reset")]
        public IActionResult Reset()
        {
            var path = Path.Combine(_env.ContentRootPath, "infrastructure", "setup.json");

            var resetSettings = new SetupSettings
            {
                IsConfigured = false,
                DbHost = "",
                DbPort = 3306,
                DbName = "",
                DbUser = "",
                DbPassword = "",
                AdminUsername = "admin",
                AdminEmail = "admin@localhost",
                AdminPassword = "Admin123!"
            };

            var json = JsonSerializer.Serialize(resetSettings, new JsonSerializerOptions { WriteIndented = true });
            System.IO.File.WriteAllText(path, json);

            return RedirectToAction("Index");
        }

        [HttpPost("")]
        public async Task<IActionResult> Setup([FromBody] SetupSettings model)
        {
            if (!ModelState.IsValid)
            {
                var allErrors = ModelState
                    .Where(e => e.Value.Errors.Count > 0)
                    .Select(e => new { Field = e.Key, Errors = e.Value.Errors.Select(x => x.ErrorMessage) });

                return BadRequest(new { error = "Modellen är ogiltig", details = allErrors });
            }

            try
            {
                // Bygg connection string säkert
                var baseConnBuilder = new MySqlConnectionStringBuilder
                {
                    Server = model.DbHost,
                    Port = (uint)model.DbPort,
                    UserID = model.DbUser,
                    Password = model.DbPassword,
                    Database = "information_schema"
                };

                // Kontrollera om databasen redan finns
                using (var conn = new MySqlConnection(baseConnBuilder.ConnectionString))
                {
                    conn.Open();
                    var cmd = new MySqlCommand("SELECT SCHEMA_NAME FROM SCHEMATA WHERE SCHEMA_NAME = @dbName", conn);
                    cmd.Parameters.AddWithValue("@dbName", model.DbName);
                    var exists = cmd.ExecuteScalar();

                    if (exists == null)
                    {
                        try
                        {
                            var createCmd = new MySqlCommand($"CREATE DATABASE `{model.DbName}`", conn);
                            createCmd.ExecuteNonQuery();
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Kunde inte skapa databasen.");
                            return BadRequest(new { error = "Databasen finns inte och kunde inte skapas.", details = ex.Message });
                        }
                    }
                }

                // Bygg EF-connection
                var efConnBuilder = new MySqlConnectionStringBuilder
                {
                    Server = model.DbHost,
                    Port = (uint)model.DbPort,
                    UserID = model.DbUser,
                    Password = model.DbPassword,
                    Database = model.DbName
                };

                var tempProvider = SetupService.BuildTemporaryServices(efConnBuilder.ConnectionString);
                using var scope = tempProvider.CreateScope();

                // Skapa databastabeller
                var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                await db.Database.MigrateAsync();

                // Sätt konfig-flagga tidigt
                model.IsConfigured = true;

                // Spara setup.json
                var filePath = Path.Combine(_env.ContentRootPath, "infrastructure", "setup.json");
                var json = JsonSerializer.Serialize(model, new JsonSerializerOptions { WriteIndented = true });
                System.IO.File.WriteAllText(filePath, json);

                // Roller och admin
                var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
                var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();

                string[] roles = { "Admin", "Chef", "Budget" };
                foreach (var role in roles)
                {
                    if (!await roleManager.RoleExistsAsync(role))
                        await roleManager.CreateAsync(new IdentityRole(role));
                }

                var existingUser = await userManager.FindByNameAsync(model.AdminUsername);
                if (existingUser == null)
                {
                    var adminUser = new ApplicationUser
                    {
                        UserName = model.AdminUsername,
                        Email = model.AdminEmail,
                        EmailConfirmed = true
                    };

                    var result = await userManager.CreateAsync(adminUser, model.AdminPassword);
                    if (!result.Succeeded)
                        return BadRequest(new { error = "Kunde inte skapa administratör", details = result.Errors });

                    await userManager.AddToRoleAsync(adminUser, "Admin");
                }

                return Ok(new { message = "Installation slutförd!" });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Fel vid installation.");
                return BadRequest(new { error = "Fel vid installation", details = ex.Message });
            }
        }

        public IActionResult SetupComplete() => View();
    }
}
