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

namespace foodmarket.Api.Controllers.Catalog;

[ApiController]
[Authorize]
[Route("api/catalog/retail-points")]
public class RetailPointsController : ControllerBase
{
    private readonly AppDbContext _db;

    public RetailPointsController(AppDbContext db) => _db = db;

    [HttpGet]
    public async Task<ActionResult<PagedResult<RetailPointDto>>> List([FromQuery] PagedRequest req, CancellationToken ct)
    {
        var q = _db.RetailPoints.Include(r => r.Store).AsNoTracking().AsQueryable();
        if (!string.IsNullOrWhiteSpace(req.Search))
        {
            var s = req.Search.Trim().ToLower();
            q = q.Where(r => r.Name.ToLower().Contains(s) || (r.Code != null && r.Code.ToLower().Contains(s)));
        }
        var total = await q.CountAsync(ct);
        q = (req.Sort, req.Desc) switch
        {
            ("code", false) => q.OrderBy(r => r.Code).ThenBy(r => r.Name),
            ("code", true) => q.OrderByDescending(r => r.Code).ThenBy(r => r.Name),
            ("store", false) => q.OrderBy(r => r.Store!.Name).ThenBy(r => r.Name),
            ("store", true) => q.OrderByDescending(r => r.Store!.Name).ThenBy(r => r.Name),
            ("address", false) => q.OrderBy(r => r.Address).ThenBy(r => r.Name),
            ("address", true) => q.OrderByDescending(r => r.Address).ThenBy(r => r.Name),
            ("isActive", false) => q.OrderBy(r => r.IsActive).ThenBy(r => r.Name),
            ("isActive", true) => q.OrderByDescending(r => r.IsActive).ThenBy(r => r.Name),
            ("name", true) => q.OrderByDescending(r => r.Name),
            _ => q.OrderBy(r => r.Name),
        };
        var items = await q
            .Skip(req.Skip).Take(req.Take)
            .Select(r => new RetailPointDto(r.Id, r.Name, r.Code, r.StoreId, r.Store!.Name,
                r.Address, r.Phone, r.FiscalSerial, r.FiscalRegNumber, r.IsActive))
            .ToListAsync(ct);
        return new PagedResult<RetailPointDto> { Items = items, Total = total, Page = req.Page, PageSize = req.Take };
    }

    [HttpGet("{id:guid}")]
    public async Task<ActionResult<RetailPointDto>> Get(Guid id, CancellationToken ct)
    {
        var r = await _db.RetailPoints.Include(x => x.Store).AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct);
        return r is null ? NotFound() : new RetailPointDto(r.Id, r.Name, r.Code, r.StoreId, r.Store!.Name,
            r.Address, r.Phone, r.FiscalSerial, r.FiscalRegNumber, r.IsActive);
    }

    [HttpPost, Authorize(Roles = "Admin")]
    public async Task<ActionResult<RetailPointDto>> Create([FromBody] RetailPointInput input, CancellationToken ct)
    {
        var store = await _db.Stores.FirstOrDefaultAsync(s => s.Id == input.StoreId, ct);
        if (store is null) return BadRequest(new { error = "Invalid StoreId" });

        var e = new RetailPoint
        {
            Name = input.Name, Code = input.Code, StoreId = input.StoreId,
            Address = input.Address, Phone = input.Phone,
            FiscalSerial = input.FiscalSerial, FiscalRegNumber = input.FiscalRegNumber,
            IsActive = input.IsActive,
        };
        _db.RetailPoints.Add(e);
        await _db.SaveChangesAsync(ct);
        return CreatedAtAction(nameof(Get), new { id = e.Id },
            new RetailPointDto(e.Id, e.Name, e.Code, e.StoreId, store.Name,
                e.Address, e.Phone, e.FiscalSerial, e.FiscalRegNumber, e.IsActive));
    }

    [HttpPut("{id:guid}"), Authorize(Roles = "Admin")]
    public async Task<IActionResult> Update(Guid id, [FromBody] RetailPointInput input, CancellationToken ct)
    {
        var e = await _db.RetailPoints.FirstOrDefaultAsync(x => x.Id == id, ct);
        if (e is null) return NotFound();
        e.Name = input.Name;
        e.Code = input.Code;
        e.StoreId = input.StoreId;
        e.Address = input.Address;
        e.Phone = input.Phone;
        e.FiscalSerial = input.FiscalSerial;
        e.FiscalRegNumber = input.FiscalRegNumber;
        e.IsActive = input.IsActive;
        await _db.SaveChangesAsync(ct);
        return NoContent();
    }

    [HttpDelete("{id:guid}"), Authorize(Roles = "Admin")]
    public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
    {
        var e = await _db.RetailPoints.FirstOrDefaultAsync(x => x.Id == id, ct);
        if (e is null) return NotFound();
        _db.RetailPoints.Remove(e);
        await _db.SaveChangesAsync(ct);
        return NoContent();
    }
}
