using Microsoft.EntityFrameworkCore;

public class GatewayRegistryService : IGatewayRegistryService
{
    private readonly AppDbContext _db;

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

    public async Task<WardGateway> RegisterAsync(Guid siteId, RegisterGatewayRequest req)
    {
        var siteExists = await _db.ClinicalSites.AnyAsync(s => s.Id == siteId);
        if (!siteExists)
            throw new NotFoundException("Clinical site not found.", "SITE_NOT_FOUND");

        var duplicate = await _db.WardGateways.AnyAsync(g =>
            g.SiteId == siteId && g.GatewayCode == req.GatewayCode);
        if (duplicate)
            throw new ConflictException(
                $"Gateway code '{req.GatewayCode}' already exists for this site.",
                "GATEWAY_CODE_CONFLICT");

        var gateway = new WardGateway(siteId, req.GatewayCode, req.Department);
        _db.WardGateways.Add(gateway);
        await _db.SaveChangesAsync();
        return gateway;
    }

    public async Task<WardGateway> GetByIdAsync(Guid id)
    {
        var gateway = await _db.WardGateways
            .AsNoTracking()
            .Include(g => g.Site)
            .FirstOrDefaultAsync(g => g.Id == id);
        if (gateway is null)
            throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");
        return gateway;
    }

    public async Task<List<WardGateway>> ListBySiteAsync(Guid siteId, string? department)
    {
        var siteExists = await _db.ClinicalSites.AnyAsync(s => s.Id == siteId);
        if (!siteExists)
            throw new NotFoundException("Clinical site not found.", "SITE_NOT_FOUND");

        var query = _db.WardGateways.AsNoTracking().Where(g => g.SiteId == siteId);
        if (!string.IsNullOrWhiteSpace(department))
            query = query.Where(g => g.Department == department);

        return await query.OrderBy(g => g.GatewayCode).ToListAsync();
    }

    public async Task<WardGateway> RecordHeartbeatAsync(
        Guid gatewayId, GatewayHeartbeatRequest req, string? authenticatedGatewayId)
    {
        if (authenticatedGatewayId is not null
            && Guid.TryParse(authenticatedGatewayId, out var authId)
            && authId != gatewayId)
            throw new ValidationException(
                "Gateway id in URL does not match X-Gateway-Id header.",
                "GATEWAY_ID_MISMATCH");

        var gateway = await _db.WardGateways.FindAsync(gatewayId);
        if (gateway is null)
            throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");

        var status = GatewayStatusExtensions.FromDbString(req.Status.ToUpperInvariant());
        gateway.RecordHeartbeat(status, req.BufferDepth, req.ReportedAtUtc);
        await _db.SaveChangesAsync();
        return gateway;
    }

    public async Task MarkOfflineAsync(Guid gatewayId)
    {
        var gateway = await _db.WardGateways.FindAsync(gatewayId);
        if (gateway is null)
            throw new NotFoundException("Ward gateway not found.", "GATEWAY_NOT_FOUND");
        gateway.MarkOffline();
        await _db.SaveChangesAsync();
    }
}