using foodmarket.Application.Common;
using foodmarket.Application.Common.Tenancy;
using foodmarket.Domain.Organizations;
using foodmarket.Infrastructure.Persistence;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace foodmarket.Api.Controllers.Organizations;

[ApiController]
[Authorize]
[Route("api/organization/employee-roles")]
public class EmployeeRolesController : ControllerBase
{
    private readonly AppDbContext _db;
    private readonly ITenantContext _tenant;

    public EmployeeRolesController(AppDbContext db, ITenantContext tenant)
    {
        _db = db; _tenant = tenant;
    }

    public record EmployeeRoleDto(
        Guid Id, string Name, string? Description,
        bool IsSystem, int SortOrder, RolePermissions Permissions);

    public record EmployeeRoleInput(
        string Name, string? Description, RolePermissions Permissions);

    [HttpGet]
    public async Task<ActionResult<PagedResult<EmployeeRoleDto>>> List(
        [FromQuery] PagedRequest req, CancellationToken ct)
    {
        var q = _db.EmployeeRoles.AsNoTracking().AsQueryable();
        if (!string.IsNullOrWhiteSpace(req.Search))
        {
            var s = req.Search.Trim().ToLower();
            q = q.Where(r => r.Name.ToLower().Contains(s));
        }
        var total = await q.CountAsync(ct);
        var items = await q
            .OrderBy(r => r.SortOrder).ThenBy(r => r.Name)
            .Skip(req.Skip).Take(req.Take)
            .Select(r => new EmployeeRoleDto(r.Id, r.Name, r.Description, r.IsSystem, r.SortOrder, r.Permissions))
            .ToListAsync(ct);
        return new PagedResult<EmployeeRoleDto>
        { Items = items, Total = total, Page = req.Page, PageSize = req.Take };
    }

    [HttpGet("{id:guid}")]
    public async Task<ActionResult<EmployeeRoleDto>> Get(Guid id, CancellationToken ct)
    {
        var r = await _db.EmployeeRoles.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct);
        return r is null ? NotFound() : new EmployeeRoleDto(r.Id, r.Name, r.Description, r.IsSystem, r.SortOrder, r.Permissions);
    }

    [HttpPost, Authorize(Roles = "SuperAdmin,Admin")]
    public async Task<ActionResult<EmployeeRoleDto>> Create([FromBody] EmployeeRoleInput input, CancellationToken ct)
    {
        var role = new EmployeeRole
        {
            Name = input.Name,
            Description = input.Description,
            IsSystem = false,
            SortOrder = await _db.EmployeeRoles.MaxAsync(r => (int?)r.SortOrder, ct) + 10 ?? 100,
            Permissions = input.Permissions ?? new RolePermissions(),
        };
        _db.EmployeeRoles.Add(role);
        await _db.SaveChangesAsync(ct);
        return CreatedAtAction(nameof(Get), new { id = role.Id },
            new EmployeeRoleDto(role.Id, role.Name, role.Description, role.IsSystem, role.SortOrder, role.Permissions));
    }

    [HttpPut("{id:guid}"), Authorize(Roles = "SuperAdmin,Admin")]
    public async Task<IActionResult> Update(Guid id, [FromBody] EmployeeRoleInput input, CancellationToken ct)
    {
        var r = await _db.EmployeeRoles.FirstOrDefaultAsync(x => x.Id == id, ct);
        if (r is null) return NotFound();
        // Системные роли — имя редактируем (можно перевести), но IsSystem нельзя
        // снять; permissions можно править, чтобы кастомизировать под себя.
        r.Name = input.Name;
        r.Description = input.Description;
        r.Permissions = input.Permissions ?? new RolePermissions();
        await _db.SaveChangesAsync(ct);
        return NoContent();
    }

    [HttpDelete("{id:guid}"), Authorize(Roles = "SuperAdmin,Admin")]
    public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
    {
        var r = await _db.EmployeeRoles.FirstOrDefaultAsync(x => x.Id == id, ct);
        if (r is null) return NotFound();
        if (r.IsSystem) return Conflict(new { error = "Системную роль удалить нельзя." });
        var inUse = await _db.Employees.AnyAsync(e => e.RoleId == id, ct);
        if (inUse) return Conflict(new { error = "Роль используется сотрудниками." });
        _db.EmployeeRoles.Remove(r);
        await _db.SaveChangesAsync(ct);
        _ = _tenant; // suppress warning
        return NoContent();
    }
}
