using foodmarket.Api.Seed;
using foodmarket.Domain.Organizations;
using foodmarket.Infrastructure.Identity;
using foodmarket.Infrastructure.Persistence;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace foodmarket.Api.Controllers;

/// <summary>Самообслуживание: регистрация новой организации с публичного
/// маркетингового сайта. Создаёт Organization + bootstrap (Stores, Roles,
/// Units, PriceTypes, Cassa) + первого Owner-Employee-AppUser-Admin.
///
/// Токены НЕ выпускаются здесь — фронт получает их обычным запросом
/// /connect/token (password grant) сразу после успешного signup. Это
/// убирает дублирование с OpenIddict и упрощает контракт. Phase 6: без
/// email-верификации (переедет в Phase 7).</summary>
[ApiController]
[Route("api/auth")]
public class AuthSignupController : ControllerBase
{
    private readonly AppDbContext _db;
    private readonly UserManager<User> _userMgr;

    public AuthSignupController(AppDbContext db, UserManager<User> userMgr)
    {
        _db = db; _userMgr = userMgr;
    }

    public record SignupInput(string Email, string Password, string OrganizationName, string Phone, string? Plan);
    public record SignupResult(Guid OrganizationId, string Email);

    [HttpPost("signup")]
    public async Task<ActionResult<SignupResult>> Signup([FromBody] SignupInput input, CancellationToken ct)
    {
        if (string.IsNullOrWhiteSpace(input.Email) || string.IsNullOrWhiteSpace(input.Password)
            || string.IsNullOrWhiteSpace(input.OrganizationName))
            return BadRequest(new { error = "Email, пароль и название обязательны." });
        if (input.Password.Length < 8)
            return BadRequest(new { error = "Пароль минимум 8 символов." });
        var normalizedPhone = foodmarket.Application.Common.PhoneNormalization.TryNormalizeKz(input.Phone);
        if (normalizedPhone is null)
            return BadRequest(new { error = foodmarket.Application.Common.PhoneNormalization.ErrorMessage });

        var existing = await _userMgr.FindByEmailAsync(input.Email);
        if (existing is not null)
        {
            // Если AppUser orphan (org удалена / он деактивирован) — реактивируем
            // его с новой organization вместо отказа. SuperAdmin'а трогать
            // нельзя: у него email тоже email и блокировка не должна давать
            // обходить вход.
            var isSuperAdmin = await _userMgr.IsInRoleAsync(existing, "SuperAdmin");
            var orgAlive = existing.OrganizationId is not null
                && await _db.Organizations.IgnoreQueryFilters()
                    .AnyAsync(o => o.Id == existing.OrganizationId.Value && !o.IsArchived, ct);
            if (isSuperAdmin || orgAlive)
                return BadRequest(new { error = "Пользователь с таким email уже зарегистрирован." });
            // Иначе — переиспользуем существующий AppUser ниже.
        }

        // 1. Organization + полный bootstrap tenant-сущностей.
        var kzt = await _db.Currencies.FirstOrDefaultAsync(c => c.Code == "KZT", ct);
        var org = new Organization
        {
            Name = input.OrganizationName.Trim(),
            CountryCode = "KZ",
            DefaultCurrencyId = kzt?.Id,
            Phone = normalizedPhone,
            Email = input.Email.Trim(),
        };
        _db.Organizations.Add(org);
        await _db.SaveChangesAsync(ct);
        await DevDataSeeder.SeedTenantReferencesAsync(_db, org.Id, ct);

        // 2. AppUser — либо новый, либо реактивируем orphan (см. выше).
        User user;
        if (existing is not null)
        {
            user = existing;
            user.OrganizationId = org.Id;
            user.IsActive = true;
            user.FullName = input.OrganizationName.Trim();
            user.Email = input.Email.Trim();
            user.EmailConfirmed = true;
            await _userMgr.UpdateAsync(user);
            // Сброс пароля на тот, что юзер ввёл сейчас.
            await _userMgr.RemovePasswordAsync(user);
            var pwRes = await _userMgr.AddPasswordAsync(user, input.Password);
            if (!pwRes.Succeeded)
            {
                _db.Organizations.Remove(org);
                await _db.SaveChangesAsync(ct);
                return BadRequest(new { error = string.Join("; ", pwRes.Errors.Select(e => e.Description)) });
            }
            // Roles: убедимся что есть Admin. SuperAdmin сюда не попадает (отсечено выше).
            if (!await _userMgr.IsInRoleAsync(user, "Admin"))
                await _userMgr.AddToRoleAsync(user, "Admin");
        }
        else
        {
            user = new User
            {
                UserName = input.Email.Trim(),
                Email = input.Email.Trim(),
                EmailConfirmed = true,
                FullName = input.OrganizationName.Trim(),
                OrganizationId = org.Id,
                IsActive = true,
            };
            var ur = await _userMgr.CreateAsync(user, input.Password);
            if (!ur.Succeeded)
            {
                _db.Organizations.Remove(org);
                await _db.SaveChangesAsync(ct);
                return BadRequest(new { error = string.Join("; ", ur.Errors.Select(e => e.Description)) });
            }
            await _userMgr.AddToRoleAsync(user, "Admin");
        }

        // 3. Owner Employee с системной ролью «Администратор».
        var adminRole = await _db.EmployeeRoles.IgnoreQueryFilters()
            .FirstAsync(r => r.OrganizationId == org.Id && r.IsSystem && r.Name == "Администратор", ct);
        _db.Employees.Add(new Employee
        {
            OrganizationId = org.Id, UserId = user.Id,
            LastName = input.OrganizationName.Trim(), FirstName = "Owner",
            Position = "Владелец", Email = input.Email.Trim(),
            RoleId = adminRole.Id, IsActive = true,
        });
        org.AccountOwnerUserId = user.Id;
        await _db.SaveChangesAsync(ct);

        return new SignupResult(org.Id, user.Email);
    }
}
