using Meezi.API.Models.Kitchen;
using Meezi.Core.Entities;
using Meezi.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace Meezi.API.Services;

public interface IKitchenStationService
{
    Task<IReadOnlyList<KitchenStationDto>> ListAsync(string cafeId, CancellationToken ct = default);
    Task<KitchenStationDto?> CreateAsync(string cafeId, CreateKitchenStationRequest request, CancellationToken ct = default);
    Task<KitchenStationDto?> UpdateAsync(string cafeId, string id, UpdateKitchenStationRequest request, CancellationToken ct = default);
    Task<bool> DeleteAsync(string cafeId, string id, CancellationToken ct = default);
}

public class KitchenStationService : IKitchenStationService
{
    private readonly AppDbContext _db;

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

    public async Task<IReadOnlyList<KitchenStationDto>> ListAsync(string cafeId, CancellationToken ct = default)
    {
        var stations = await _db.KitchenStations
            .Where(s => s.CafeId == cafeId)
            .OrderBy(s => s.SortOrder)
            .ThenBy(s => s.Name)
            .Select(s => new
            {
                s.Id,
                s.BranchId,
                s.Name,
                s.PrinterIp,
                s.PrinterPort,
                s.SortOrder,
                CategoryCount = s.Categories.Count(c => c.DeletedAt == null)
            })
            .ToListAsync(ct);

        return stations.Select(s => new KitchenStationDto(
            s.Id, s.BranchId, s.Name, s.PrinterIp, s.PrinterPort, s.SortOrder, s.CategoryCount)).ToList();
    }

    public async Task<KitchenStationDto?> CreateAsync(
        string cafeId,
        CreateKitchenStationRequest request,
        CancellationToken ct = default)
    {
        if (!string.IsNullOrEmpty(request.BranchId))
        {
            var branchOk = await _db.Branches.AnyAsync(
                b => b.Id == request.BranchId && b.CafeId == cafeId, ct);
            if (!branchOk) return null;
        }

        var entity = new KitchenStation
        {
            CafeId = cafeId,
            BranchId = request.BranchId,
            Name = request.Name.Trim(),
            PrinterIp = string.IsNullOrWhiteSpace(request.PrinterIp) ? null : request.PrinterIp.Trim(),
            PrinterPort = request.PrinterPort > 0 ? request.PrinterPort : 9100,
            SortOrder = request.SortOrder
        };

        _db.KitchenStations.Add(entity);
        await _db.SaveChangesAsync(ct);
        return await MapAsync(cafeId, entity.Id, ct);
    }

    public async Task<KitchenStationDto?> UpdateAsync(
        string cafeId,
        string id,
        UpdateKitchenStationRequest request,
        CancellationToken ct = default)
    {
        var entity = await _db.KitchenStations
            .FirstOrDefaultAsync(s => s.Id == id && s.CafeId == cafeId, ct);
        if (entity is null) return null;

        if (request.Name is not null) entity.Name = request.Name.Trim();
        if (request.BranchId is not null)
        {
            if (!string.IsNullOrEmpty(request.BranchId))
            {
                var branchOk = await _db.Branches.AnyAsync(
                    b => b.Id == request.BranchId && b.CafeId == cafeId, ct);
                if (!branchOk) return null;
            }

            entity.BranchId = string.IsNullOrEmpty(request.BranchId) ? null : request.BranchId;
        }

        if (request.PrinterIp is not null)
            entity.PrinterIp = string.IsNullOrWhiteSpace(request.PrinterIp) ? null : request.PrinterIp.Trim();
        if (request.PrinterPort.HasValue)
            entity.PrinterPort = request.PrinterPort.Value > 0 ? request.PrinterPort.Value : 9100;
        if (request.SortOrder.HasValue)
            entity.SortOrder = request.SortOrder.Value;

        await _db.SaveChangesAsync(ct);
        return await MapAsync(cafeId, id, ct);
    }

    public async Task<bool> DeleteAsync(string cafeId, string id, CancellationToken ct = default)
    {
        var entity = await _db.KitchenStations
            .FirstOrDefaultAsync(s => s.Id == id && s.CafeId == cafeId, ct);
        if (entity is null) return false;

        var categories = await _db.MenuCategories
            .Where(c => c.KitchenStationId == id && c.CafeId == cafeId)
            .ToListAsync(ct);
        foreach (var cat in categories)
            cat.KitchenStationId = null;

        entity.DeletedAt = DateTime.UtcNow;
        await _db.SaveChangesAsync(ct);
        return true;
    }

    private async Task<KitchenStationDto?> MapAsync(string cafeId, string id, CancellationToken ct)
    {
        var s = await _db.KitchenStations
            .Where(x => x.Id == id && x.CafeId == cafeId)
            .Select(x => new
            {
                x.Id,
                x.BranchId,
                x.Name,
                x.PrinterIp,
                x.PrinterPort,
                x.SortOrder,
                CategoryCount = x.Categories.Count(c => c.DeletedAt == null)
            })
            .FirstOrDefaultAsync(ct);

        return s is null
            ? null
            : new KitchenStationDto(s.Id, s.BranchId, s.Name, s.PrinterIp, s.PrinterPort, s.SortOrder, s.CategoryCount);
    }
}
