using foodmarket.Application.Common.Tenancy;
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")]
public class OrganizationSettingsController : ControllerBase
{
    private readonly AppDbContext _db;
    private readonly ITenantContext _tenant;

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

    public record OrgSettingsDto(
        Guid Id,
        string Name,
        string CountryCode,
        Guid? DefaultCurrencyId,
        string? DefaultCurrencyCode,
        string? DefaultCurrencySymbol,
        bool MultiCurrencyEnabled,
        // VAT read-only: из страны организации (countries.VatRate). Источник правды — справочник стран.
        decimal VatRate,
        bool ShowVatEnabledOnProduct,
        bool ShowServiceOnProduct,
        bool ShowMarkedOnProduct,
        bool ShowMinMaxStock,
        bool AllowFractionalPrices,
        bool ShowReferencePriceOnProduct,
        bool ShowCountryOfOriginOnProduct,
        bool ShowDescriptionOnProduct);

    // DefaultCurrencyId не принимается — он read-only, выводится из страны (Country.DefaultCurrencyId).
    public record OrgSettingsInput(
        string Name,
        string CountryCode,
        bool MultiCurrencyEnabled,
        bool ShowVatEnabledOnProduct,
        bool ShowServiceOnProduct,
        bool ShowMarkedOnProduct,
        bool ShowMinMaxStock,
        bool AllowFractionalPrices,
        bool ShowReferencePriceOnProduct,
        bool ShowCountryOfOriginOnProduct,
        bool ShowDescriptionOnProduct);

    [HttpGet("settings")]
    public async Task<ActionResult<OrgSettingsDto>> Get(CancellationToken ct)
    {
        var orgId = _tenant.OrganizationId ?? throw new InvalidOperationException("No tenant.");
        var o = await _db.Organizations
            .Include(o => o.DefaultCurrency)
            .FirstOrDefaultAsync(o => o.Id == orgId, ct);
        if (o is null) return NotFound();
        var vat = await ReadVatRateAsync(o.CountryCode, ct);
        return Project(o, vat);
    }

    [HttpPut("settings"), Authorize(Roles = "Admin")]
    public async Task<ActionResult<OrgSettingsDto>> Update([FromBody] OrgSettingsInput input, CancellationToken ct)
    {
        var orgId = _tenant.OrganizationId ?? throw new InvalidOperationException("No tenant.");
        var o = await _db.Organizations
            .Include(o => o.DefaultCurrency)
            .FirstOrDefaultAsync(o => o.Id == orgId, ct);
        if (o is null) return NotFound();

        o.Name = input.Name;
        o.CountryCode = input.CountryCode;
        // Валюта организации жёстко следует за страной — не принимается от клиента.
        o.DefaultCurrencyId = await _db.Countries
            .Where(c => c.Code == input.CountryCode)
            .Select(c => c.DefaultCurrencyId)
            .FirstOrDefaultAsync(ct);
        o.MultiCurrencyEnabled = input.MultiCurrencyEnabled;
        o.ShowVatEnabledOnProduct = input.ShowVatEnabledOnProduct;
        o.ShowServiceOnProduct = input.ShowServiceOnProduct;
        o.ShowMarkedOnProduct = input.ShowMarkedOnProduct;
        o.ShowMinMaxStock = input.ShowMinMaxStock;
        o.AllowFractionalPrices = input.AllowFractionalPrices;
        o.ShowReferencePriceOnProduct = input.ShowReferencePriceOnProduct;
        o.ShowCountryOfOriginOnProduct = input.ShowCountryOfOriginOnProduct;
        o.ShowDescriptionOnProduct = input.ShowDescriptionOnProduct;
        await _db.SaveChangesAsync(ct);

        await _db.Entry(o).Reference(x => x.DefaultCurrency).LoadAsync(ct);
        var vat = await ReadVatRateAsync(o.CountryCode, ct);
        return Project(o, vat);
    }

    private async Task<decimal> ReadVatRateAsync(string countryCode, CancellationToken ct)
    {
        var rate = await _db.Countries
            .Where(c => c.Code == countryCode)
            .Select(c => (decimal?)c.VatRate)
            .FirstOrDefaultAsync(ct);
        return rate ?? 0m;
    }

    private static OrgSettingsDto Project(foodmarket.Domain.Organizations.Organization o, decimal vat) => new(
        o.Id, o.Name, o.CountryCode,
        o.DefaultCurrencyId,
        o.DefaultCurrency?.Code,
        o.DefaultCurrency?.Symbol,
        o.MultiCurrencyEnabled,
        vat,
        o.ShowVatEnabledOnProduct,
        o.ShowServiceOnProduct,
        o.ShowMarkedOnProduct,
        o.ShowMinMaxStock,
        o.AllowFractionalPrices,
        o.ShowReferencePriceOnProduct,
        o.ShowCountryOfOriginOnProduct,
        o.ShowDescriptionOnProduct);
}
