using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;
using ProSmart.Constant.EventType;
using ProSmart.Core;
using ProSmart.Dtos.Base.TenderService;
using ProSmart.Dtos.Base.TenderService.PsTenderBaseItem;
using ProSmart.Dtos.EntityDto.AuthService;
using ProSmart.Dtos.EntityDto.DraftService;
using ProSmart.Dtos.EntityDto.TenderingService;
using ProSmart.Dtos.EntityDto.WorkflowService;
using ProSmart.Dtos.Enumurable.FileServices;
using ProSmart.Dtos.EventDtos;
using ProSmart.Dtos.EventDtos.ActionEvent.FileServices;
using ProSmart.Dtos.EventDtos.ActionEvent.TenderingServices;
using ProSmart.Dtos.EventDtos.QueryEvent.ReportingService;
using ProSmart.Dtos.ObjectConverter;
using ProSmart.ReportingServices.Handlers;
using ProSmart.ReportingServices.Helper;
using ProSmart.ReportingServices.Modules;
using ReportConsole;
using static ProSmart.Dtos.Base.TenderService.PsTenderBaseItem.ShortListingMethodsBase;

namespace ProSmart.ReportingServices.Reports
{
    internal class TenderProposal : ReportBase
    {
        private ReportingServicesDbTransactionHelper dbHelper;
        public TenderProposal(FileHandler fileHandler, BucketPathHandler bucketPathHandler, ReportingServicesDbContext dbContext, GenerateReportQueryDto dto, string userId) 
            : base(fileHandler, bucketPathHandler, dbContext, dto, userId)
        {
            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        }

        public TenderProposal(ILogger<GenerateReportQueryDto> logger, FileHandler fileHandler, BucketPathHandler bucketPathHandler, ReportingServicesDbContext dbContext, GenerateReportQueryDto dto, string userId)
            : base(logger, fileHandler, bucketPathHandler, dbContext, dto, userId)
        {
            contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
        }

        public async Task<ProFileItemUpdateDto> Create()
        {
            // get oid from frontend query
            //var filter = BsonDocument.Parse(_dto.JsonQuery);
            //var mongoClient = (_dbContext as AbstractDbContext).MongoClient;
            //var projection = Builders<BsonDocument>.Projection.Include("_id");
            //var result = mongoClient.GetDatabase("TenderingServices").GetCollection<BsonDocument>("ProTenders").Find(filter).Project(projection).ToList();
            //
            var path = GetTemplateFilePath("401TenderProposalTemplate");
            using (var docStream = await _fileHandler.DownloadAsStream(path))
            {
                dbHelper = new ReportingServicesDbTransactionHelper(_dbContext);

                var tender = dbHelper.GetReadOnlyCollectionQuery<ProTendersEntityDto>().FirstOrDefault(item => item.Id == _dto.ObjectId);
                var psForm = dbHelper.GetReadOnlyCollectionQuery<ProTenderPsFormEntityDto>().FirstOrDefault(item => item.Id == tender.PsRef);
                var ProEform = dbHelper.GetReadOnlyCollectionQuery<ProEformEntityDto>().FirstOrDefault(item => item.RequestNo == tender.PsFormRef);

                using (var wgen = new WordReportGenerator(docStream))
                {
                    if (tender != null)
                    {
                        FillDocument(wgen, tender, psForm, ProEform);
                    }
                    using (MemoryStream outputStream = new MemoryStream())
                    {
                        wgen.Save(outputStream);
                        var proFileDto = await SendToMinio(outputStream, "TenderProposal.docx");
                        return proFileDto;
                    }

                }
            }
        }


        private void FillDocument(WordReportGenerator wgen, ProTendersEntityDto entity, ProTenderPsFormEntityDto psForm, ProEformEntityDto proForm)
        {
            var noVal = "";
            // word content variable
            var placeHolderContent = new Dictionary<string, string>();
            placeHolderContent["templateprno"] = noVal; //TODO: PR No.
            placeHolderContent["templatetender"] = entity?.TenderRef ?? "";
            placeHolderContent["templatedepartment"] = psForm?.ProcurementStrategyInfo?.BudgetDivision ?? "";
            placeHolderContent["templatedescription"] = entity?.RequisitionItems?.Background?? ""; // TODO: Description of Service / Product
            placeHolderContent["templateestimated"] = noVal; // TODO: Estimated Value of the Contract
            placeHolderContent["templatejustifications"] = noVal; //TODO: Justification for the Contract
            placeHolderContent["templateexpecteddelivery"] = entity?.RequisitionItems?.ExpectedDelivery?? "";
            placeHolderContent["templatecontractperiod"] = noVal; // TODO: Contract Period
            placeHolderContent["templateweightingjustification"] = entity?.AssessmentMethods?.Justification?? "";
            placeHolderContent["templateothermatters"] = noVal; // TODO: Other Matters
            placeHolderContent["templatenumbersheet"] = noVal; // TODO: Number of Supplementary Sheets
            placeHolderContent["templatetechnical"] = entity?.AssessmentMethods?.TechnicalWeighting?.ToString() ?? "";
            placeHolderContent["templateprice"] = entity?.AssessmentMethods?.PriceWeighting?.ToString() ?? "";
            placeHolderContent["templatetotalscore"] = entity?.AssessmentMethods?.TechnicalWeighting.ToString() ?? ""; //TODO: Total Technical Score
            placeHolderContent["templatepassingmark"] = entity?.AssessmentMethods?.TechnicalPassScore.ToString() ?? ""; // TODO: Overall Passing Marks

            var checkedDescriptionList = new Dictionary<string, bool>();
            checkedDescriptionList["cbOT"] = false;
            checkedDescriptionList["cbST"] = false;
            
            /* TODO: Type of Tender Method
            if(entity.TypeOfTender)
            */

            if (psForm?.ProcurementMethod?.TenderingProcedure == Dtos.Enumurable.TenderingService.BiddingProcedureEnum.SingleEnvelope)
            {
                checkedDescriptionList["cbSE"] = true;
                checkedDescriptionList["cbTE"] = false;
            }
            else if (psForm?.ProcurementMethod?.TenderingProcedure == Dtos.Enumurable.TenderingService.BiddingProcedureEnum.TwoEnvelope)
            {
                checkedDescriptionList["cbSE"] = false;
                checkedDescriptionList["cbTE"] = true;
            }
            else
            {
                checkedDescriptionList["cbSE"] = false;
                checkedDescriptionList["cbTE"] = false;
            }

            // TODO: Weighting Justification
            checkedDescriptionList["cbTPW1"] = false;
            checkedDescriptionList["cbTPW2"] = false;
            checkedDescriptionList["cbTPW3"] = false;
            checkedDescriptionList["cbTPW4"] = false;
            
            // TODO: Checklist of Supporting Documents
            checkedDescriptionList["cbDTD"] = false;
            checkedDescriptionList["cbPQE"] = false;
            
            // TODO: Check Sufficient Project Budget
            checkedDescriptionList["pbYes"] = false;
            checkedDescriptionList["pbNo"] = false;
            
            // TODO: Pre-qualification
            checkedDescriptionList["peYes"] = false;
            checkedDescriptionList["peNo"] = false;
            
            // TODO: Draft Tender Document Submission status
            checkedDescriptionList["rpYes"] = false;
            checkedDescriptionList["rpNo"] = false;

            var supplierTable = new List<List<string>>();
            foreach (var s in entity?.ShortListingMethods?.SupplierList?.ShortlistedSuppliers ?? Enumerable.Empty<ShortlistedSupplierItem>())
            {
                if (s != null)
                {
                    var col1 = s.Supplier?.CompanyName;
                    var col2 = s.Supplier?.ClassificationIndicator;
                    var col3 = s.SelectionMethod;
                    var col4 = s.Remarks;
                    supplierTable.Add(new List<string> { col1, col2?.ToString(), col3?.ToString(), col4 });
                }
            }

            // not provided
            var paymentTable = new List<List<string>>();
            //PaymentTable.Add(new List<string> { "col11", "10%" });

            var markingTable = new List<List<string>>();
            foreach (var r in entity?.AssessmentMethods?.AssessmentRound ?? Enumerable.Empty<AssessmentRoundObj>())
            {
                if (r != null && r.AssessmentItems != null)
                {
                    foreach (var a in r.AssessmentItems)
                    {
                        if (a != null)
                        {
                            var col1 = r.Round + " " + a.CriteriaName;
                            var col2 = ""; //a?.Weighting + "%";
                            var col3 = a?.PassingMark + "%";
                            markingTable.Add(new List<string> { col1, col2, col3 });
                        }
                    }
                }
            }



            var tapTable = new List<List<string>>();
            var staffNames = new List<string>();
            var staffDepartments = new List<string>();
            var staffTitle = new List<string>();
            foreach (var ap in entity.AssessmentPanelInfo.AssessmentGroup)
            {
                staffNames.Add(ap.User[0].UserName);
                staffDepartments.Add(ap.User[0].Department[0].Code);
                staffTitle.Add(ap.RoleName.ToString());
            }
            tapTable.Add(staffNames);
            tapTable.Add(staffDepartments);
            tapTable.Add(staffTitle);

            var submittedByUserDeptTable = new List<List<string>>();
            submittedByUserDeptTable.Add(new List<string>{proForm.Requester[0].UserName});
            var reviewers = entity.ApprovalRoute.UserList.Where(u => u.Level == "1").ToList();
            var approvers = entity.ApprovalRoute.UserList.Where(u => u.Level == "4").ToList();
            
            for (int i = 0; i < 2; i++)
            {
                var _ud = dbHelper.GetReadOnlyCollectionQuery<ProUsersEntityDto>()
                    .FirstOrDefault(u => u.Id == reviewers[i].List[0].User[0].UserId);
                if (_ud != null)
                {
                    submittedByUserDeptTable.Add(new List<string>{_ud.NameEng});
                }
            }
            for (int i = 0; i < 2; i++)
            {
                var _ud = dbHelper.GetReadOnlyCollectionQuery<ProUsersEntityDto>()
                    .FirstOrDefault(u => u.Id == approvers[i].List[0].User[0].UserId);
                if (_ud != null)
                {
                    submittedByUserDeptTable.Add(new List<string>{_ud.NameEng});
                }
            }
            

            var review1Table = new List<List<string>>();
            for (int i = 0; i < 2; i++)
            {
                var _ud = dbHelper.GetReadOnlyCollectionQuery<ProUsersEntityDto>()
                    .FirstOrDefault(u => u.Id == reviewers[i].List[0].User[0].UserId);
                if (_ud != null)
                {
                    review1Table.Add(new List<string>{_ud.NameEng});
                }
            }

            var review2Table = new List<List<string>>();
            for (int i = 0; i < 2; i++)
            {
                var _ud = dbHelper.GetReadOnlyCollectionQuery<ProUsersEntityDto>()
                    .FirstOrDefault(u => u.Id == reviewers[i].List[0].User[0].UserId);
                if (_ud != null)
                {
                    review2Table.Add(new List<string>{_ud.NameEng});
                }
            }

            wgen.ReplaceHolder(placeHolderContent);
            wgen.CheckboxItems(checkedDescriptionList);
            wgen.FillRealTable("Name of Supplier", supplierTable, 1, 0);
            wgen.FillRealTable("Assessment Criteria", markingTable, 1, 0);
            wgen.FillRealTable("Proposed Payment Terms/Schedule", paymentTable, 3, 0);
            wgen.FillRealTable("User Department", tapTable, 2, 1);
            wgen.FillRealTable("Submitted by User Department", submittedByUserDeptTable, 2, 1);
            wgen.FillRealTable("Reviewed by Procurement Section", review1Table, 2, 1);
            wgen.FillRealTable("A copy of the Draft Tender Documents", review2Table, 2, 1);
            
        }
    }
}


請將以上程式碼中可能出現Object Null Reference的部份加入null check，以防程式報錯而中止