using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NexusIdentity.Api.Data;
using NexusIdentity.Api.Models;

namespace NexusIdentity.Api.Controllers;

[ApiController]
[Route("api/organizations")]
public sealed class OrganizationsController : ControllerBase
{
    private readonly IdentityDbContext _db;

    public OrganizationsController(IdentityDbContext db)
    {
        _db = db;
    }

    [HttpGet]
    public async Task<IActionResult> List(CancellationToken ct)
    {
        var orgs = await _db.Organizations
            .AsNoTracking()
            .OrderBy(o => o.Name)
            .Select(o => new OrganizationDto
            {
                Id = o.Id,
                Name = o.Name,
                IsActive = o.IsActive,
                UserCount = o.Users.Count,
                DeviceCount = o.Devices.Count,
                CreatedAtUtc = o.CreatedAtUtc,
            })
            .ToListAsync(ct);

        return Ok(orgs);
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(string id, CancellationToken ct)
    {
        var org = await _db.Organizations
            .AsNoTracking()
            .Where(o => o.Id == id)
            .Select(o => new OrganizationDto
            {
                Id = o.Id,
                Name = o.Name,
                IsActive = o.IsActive,
                UserCount = o.Users.Count,
                DeviceCount = o.Devices.Count,
                CreatedAtUtc = o.CreatedAtUtc,
            })
            .FirstOrDefaultAsync(ct);

        return org is null ? NotFound() : Ok(org);
    }

    [HttpPost]
    public async Task<IActionResult> Create([FromBody] CreateOrganizationRequest request, CancellationToken ct)
    {
        if (string.IsNullOrWhiteSpace(request.Id) || string.IsNullOrWhiteSpace(request.Name))
        {
            return BadRequest(new { error = "Id and Name are required." });
        }

        if (await _db.Organizations.AnyAsync(o => o.Id == request.Id, ct))
        {
            return Conflict(new { error = "Organization already exists." });
        }

        var org = new OrganizationEntity
        {
            Id = request.Id.Trim(),
            Name = request.Name.Trim(),
            IsActive = true,
            CreatedAtUtc = DateTime.UtcNow,
        };

        _db.Organizations.Add(org);
        await _db.SaveChangesAsync(ct);

        return CreatedAtAction(nameof(Get), new { id = org.Id }, new OrganizationDto
        {
            Id = org.Id,
            Name = org.Name,
            IsActive = org.IsActive,
            CreatedAtUtc = org.CreatedAtUtc,
        });
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> Update(string id, [FromBody] UpdateOrganizationRequest request, CancellationToken ct)
    {
        var org = await _db.Organizations.FirstOrDefaultAsync(o => o.Id == id, ct);
        if (org is null)
        {
            return NotFound();
        }

        if (!string.IsNullOrWhiteSpace(request.Name))
        {
            org.Name = request.Name.Trim();
        }

        if (request.IsActive.HasValue)
        {
            org.IsActive = request.IsActive.Value;
        }

        await _db.SaveChangesAsync(ct);
        return Ok(new OrganizationDto
        {
            Id = org.Id,
            Name = org.Name,
            IsActive = org.IsActive,
            CreatedAtUtc = org.CreatedAtUtc,
        });
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(string id, CancellationToken ct)
    {
        var org = await _db.Organizations.FirstOrDefaultAsync(o => o.Id == id, ct);
        if (org is null)
        {
            return NotFound();
        }

        var hasUsers = await _db.Users.AnyAsync(u => u.OrganizationId == id, ct);
        var hasDevices = await _db.Devices.AnyAsync(d => d.OrganizationId == id, ct);
        if (hasUsers || hasDevices)
        {
            return BadRequest(new { error = "Organization has linked users or devices." });
        }

        _db.Organizations.Remove(org);
        await _db.SaveChangesAsync(ct);
        return NoContent();
    }
}

public sealed class OrganizationDto
{
    public required string Id { get; init; }
    public required string Name { get; init; }
    public bool IsActive { get; init; }
    public int UserCount { get; init; }
    public int DeviceCount { get; init; }
    public DateTime CreatedAtUtc { get; init; }
}

public sealed class CreateOrganizationRequest
{
    public required string Id { get; init; }
    public required string Name { get; init; }
}

public sealed class UpdateOrganizationRequest
{
    public string? Name { get; init; }
    public bool? IsActive { get; init; }
}
