using Fast.Web.Models;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace Fast.Web.Controllers;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class QualityBankController(MyDbContext context) : ODataController
{
    private readonly MyDbContext db = context;
    private readonly AuthorizationHelper authHelper = new(Main.IsAuthenticationEnabled);

    [Permission("Quality Bank Adjustment", PermissionType.View)]
    [Route("/odata/GetQualityBankItems")]
    public IActionResult GetItems(ODataQueryOptions<QualityBankItem> queryOptions, bool isExport, bool showOriginal)
    {
        queryOptions = Util.GetQueryOptionsWithConvertedDates(queryOptions);
        var itemsQueryable = GetItemsInternal(showOriginal);
        var items = (queryOptions.ApplyTo(itemsQueryable) as IEnumerable<QualityBankItem>)?.ToList();

        if (isExport)
            return File(Util.Excel.GetExportFileStream(items), "application/octet-stream");
        else
            return Ok(items);
    }

    [Permission("Quality Bank Adjustment", PermissionType.View)]
    [Route("[action]")]
    public IQueryable<QualityBankItem> GetItemsInternal(bool showOriginal)
    {
        IQueryable<QualityBankAdjustment> query;

        if (showOriginal)
            query = db.QualityBankAdjustments;
        else
        {
            var maxDates = (
                from q in db.QualityBankAdjustments
                group q by new
                {
                    ContractId = q.Contract.Id,
                    q.Month
                } into g
                select new { g.Key.ContractId, g.Key.Month, MaxAsOfDate = g.Max(x => x.AsOfDate) }
            );

            query = (
                from q in db.QualityBankAdjustments
                join md in maxDates on new { q.ContractId, q.Month, q.AsOfDate } equals new { md.ContractId, md.Month, AsOfDate = md.MaxAsOfDate }
                select q
            );
        }

        var itemsQueryable = query.Select(q => new QualityBankItem
        {
            Id = q.Id,
            Month = q.Month,
            ContractNum = q.Contract.ContractNum,
            CounterPartyName = q.Contract.Counterparty.Name,
            AsOfDate = q.AsOfDate,
        });

        return itemsQueryable;
    }

    [Permission("Quality Bank Adjustment", PermissionType.View)]
    [Route("[action]")]
    public async Task<IActionResult> GetRequiredData()
    {
        var hasModifyPermission = await authHelper.IsAuthorizedAsync(User, "Quality Bank Adjustment", PermissionType.Modify);
        var meters = (await DataHelper.GetMetersByProductAsync(Enums.ProductCategory.CrudeOil)).Select(q => new { q.MeterId, q.MeterName }).ToList();

        var counterparties = (await DataHelper.GetCounterpartiesAsync(false, Enums.ProductCategory.CrudeOil))
            .Select(x => new { counterpartyId = x.EntityId, counterpartyName = x.FullName }).ToList();

        var contracts = await (
            from q in db.Contracts
            where q.Product.CategoryId == (int)Enums.ProductCategory.CrudeOil
            orderby q.ContractName
            select new { ContractId = q.Id, q.ContractNum, q.CounterpartyId }
        ).ToListAsync();

        var result = new { hasModifyPermission, meters, counterparties, contracts };
        return Ok(result);
    }

    [Permission("Quality Bank Adjustment", PermissionType.View)]
    [Route("[action]")]
    public async Task<IActionResult> GetDetail(int id)
    {
        var detail = await (
            from q in db.QualityBankAdjustments
            where q.Id == id
            select new QualityBankDetail
            {
                Id = q.Id,
                Month = q.Month,
                CounterpartyId = q.Contract.CounterpartyId,
                ContractId = q.ContractId,
                AsOfDate = q.AsOfDate,
                DetailMeters = q.QualityBankAdjustmentDetails.Select(qd => new QualityBankDetailMeter
                {
                    MeterId = qd.MeterId,
                    TitleMeterId = qd.TitleMeterId,
                    Qb1 = qd.Qb1,
                    Qb2 = qd.Qb2,
                    Qb3 = qd.Qb3,
                    Qb4 = qd.Qb4,
                })

            }
        ).AsNoTracking().FirstAsync();

        return Ok(detail);
    }

    public enum SaveType
    {
        New = 1,
        Normal = 2
    }

    [Permission("Quality Bank Adjustment", PermissionType.Modify)]
    [Route("[action]")]
    public async Task<IActionResult> SaveDetail(QualityBankDetail detailItem, SaveType saveType)
    {
        int resultId = 0;
        var isNewDetail = detailItem.Id == 0 || detailItem.Id == null;

        await db.Database.CreateExecutionStrategy().Execute(async () =>
        {
            using var dbContextTransaction = await db.Database.BeginTransactionAsync();
            QualityBankAdjustment? dbItem = null;

            if (!isNewDetail && saveType != SaveType.New)
            {
                dbItem = await db.QualityBankAdjustments.Where(x => x.Id == detailItem.Id).FirstAsync();
                dbItem.ContractId = detailItem.ContractId;
                dbItem.AsOfDate = detailItem.AsOfDate;
                dbItem.Month = detailItem.Month;

                var existingDetails = await db.QualityBankAdjustmentDetails.Where(x => x.QualityBankAdjustmentId == detailItem.Id).ToListAsync();
                db.QualityBankAdjustmentDetails.RemoveRange(existingDetails);

                foreach (var meterItem in detailItem.DetailMeters)
                {
                    db.QualityBankAdjustmentDetails.Add(new QualityBankAdjustmentDetail
                    {
                        QualityBankAdjustmentId = detailItem.Id ?? 0,
                        MeterId = meterItem.MeterId,
                        TitleMeterId = meterItem.TitleMeterId ?? 0,
                        Qb1 = meterItem.Qb1,
                        Qb2 = meterItem.Qb2,
                        Qb3 = meterItem.Qb3,
                        Qb4 = meterItem.Qb4,
                    });
                }
                resultId = dbItem.Id;
            }
            if (isNewDetail || saveType == SaveType.New)
            {
                dbItem = new QualityBankAdjustment
                {
                    ContractId = detailItem.ContractId,
                    AsOfDate = detailItem.AsOfDate,
                    Month = detailItem.Month
                };
                db.QualityBankAdjustments.Add(dbItem);
                await db.SaveChangesAsync();

                foreach (var meterItem in detailItem.DetailMeters)
                {
                    db.QualityBankAdjustmentDetails.Add(new QualityBankAdjustmentDetail
                    {
                        QualityBankAdjustmentId = dbItem.Id,
                        MeterId = meterItem.MeterId,
                        TitleMeterId = meterItem.TitleMeterId ?? 0,
                        Qb1 = meterItem.Qb1,
                        Qb2 = meterItem.Qb2,
                        Qb3 = meterItem.Qb3,
                        Qb4 = meterItem.Qb4,
                    });
                }

                resultId = dbItem.Id;
            }

            await db.SaveChangesAsync();
            await dbContextTransaction.CommitAsync();

            if (dbItem != null)
                resultId = dbItem.Id;
        });

        return Ok(resultId);
    }

    [Permission("Quality Bank Adjustment", PermissionType.Modify)]
    [Route("[action]/{id}")]
    public async Task<IActionResult> DeleteDetail(int id)
    {
        QualityBankAdjustment dbItem = await db.QualityBankAdjustments.Where(x => x.Id == id).FirstAsync();
        db.QualityBankAdjustments.Remove(dbItem);
        await db.SaveChangesAsync();

        return Ok();
    }
}


