using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iRIS.Framework.Data.Services.Client.Interfaces;
using iRIS.Framework.Entity.Metadata.Manager.Interfaces;
using iRIS.InsuranceCore.Code.CustomProcesses.BasketPreparationProcess.Enums;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.KaskoCore.Code.Constants;
using iRIS.KaskoCore.Entities;
using iRIS.KaskoCore.Printing.ViewModels;
using iRIS.Printing.Generated.ViewModels;

namespace iRIS.KaskoCore.Printing.Code
{
    public class KaskoModificationPrntViewModelGenerator : IKaskoModificationPrntViewModelGenerator
    {
        private readonly int[] _riskDegreeChanges = { 7 };
        private readonly int[] _driversListChanges = { 18 };
        private readonly int[] _autoRegistrationChanges = { 25 };
        private readonly int[] _autoStartChanges = { 55 };
        private readonly int[] _informationChanges = { 26, 27, 28, 29, 30, 35, 36, 37, 40 };

        private readonly string[] _notPreviewStatusTypes = { EntityStatusType.Signed.ToString(), EntityStatusType.PolicyIssued.ToString() };

        private readonly ICachedQueryServiceInvoker _queryService;
        private readonly IPathManager _pathManager;

        public KaskoModificationPrntViewModelGenerator(
            ICachedQueryServiceInvoker queryService,
            IPathManager pathManager)
        {
            _queryService = queryService;
            _pathManager = pathManager;
        }

        public PrntKaskoAdditionalAgreementViewModel GetKaskoModificationAdditionalAgreementViewModel(Basket basket)
        {
            var agreement = new PrntKaskoAdditionalAgreementViewModel();
            var deal = basket.GetKaskoDeal();
            var auto = deal.GetAuto();
            var drivers = deal.AutoDeal.Drivers;
            var insurant = deal.GetInsurantPerson();
            var tsIdentityCard = deal.AutoDeal.TsIdentityCard;

            var modifications = _queryService.GetByExpression<KaskoModificationsInBasket>(
                x => x.Where(m => m.BasketNumber == basket.Number));
            var agreements = _queryService.GetByExpression<KaskoModificationsAgreementsInBasket>(
                x => x.Where(m => m.BasketNumber == basket.Number));

            var needToPrintRiskDegreeChangeAgreement = modifications.Any(x => _riskDegreeChanges.Contains(x.ModificationListForKaskoCode));
            var needToPrintDriversListChangeAgreement = modifications.Any(x => _driversListChanges.Contains(x.ModificationListForKaskoCode));
            var needToPrintAutoRegistrationChangeAgreement = modifications.Any(x => _autoRegistrationChanges.Contains(x.ModificationListForKaskoCode));
            var needToPrintAutoStartChangeAgreement = modifications.Any(x => _autoStartChanges.Contains(x.ModificationListForKaskoCode));
            var needToPrintInformationChangeAgreement = modifications.Any(x => _informationChanges.Contains(x.ModificationListForKaskoCode));

            agreement = new PrntKaskoAdditionalAgreementViewModel
            {
                IsPreview = !_notPreviewStatusTypes.Contains(deal.DealStatusCode),
                IsMultidrive = deal.AutoDeal.IsMultidrive,
                PolicyNumber = deal.PolicyNumber,
                PolicyDate = deal.DateStart.Value,
                ChangesStartDate = deal.ChangesStartDate.Value,
                RiskDegreeChangeAgreement = new PrntChangeAgreementViewModel
                {
                    IsVisible = needToPrintRiskDegreeChangeAgreement,
                    Number = needToPrintRiskDegreeChangeAgreement ? GetAgreementNumber(agreements, ModificationAgreementNames.RiskDegreeChangeAgreement) : null
                },
                DriversListChangeAgreement = new PrntChangeAgreementViewModel
                {
                    IsVisible = needToPrintDriversListChangeAgreement,
                    Number = needToPrintDriversListChangeAgreement ? GetAgreementNumber(agreements, ModificationAgreementNames.DriversListChangeAgreement) : null
                },
                AutoRegistrationChangeAgreement = new PrntChangeAgreementViewModel
                {
                    IsVisible = modifications.Any(x => _autoRegistrationChanges.Contains(x.ModificationListForKaskoCode)),
                    Number = needToPrintAutoRegistrationChangeAgreement ? GetAgreementNumber(agreements, ModificationAgreementNames.AutoRegistrationChangeAgreement) : null
                },
                AutoStartChangeAgreement = new PrntChangeAgreementViewModel
                {
                    IsVisible = modifications.Any(x => _autoStartChanges.Contains(x.ModificationListForKaskoCode)),
                    Number = needToPrintAutoStartChangeAgreement ? GetAgreementNumber(agreements, ModificationAgreementNames.AutoStartChangeAgreement) : null
                },
                InformationChangeAgreement = new PrntChangeAgreementViewModel
                {
                    IsVisible = modifications.Any(x => _informationChanges.Contains(x.ModificationListForKaskoCode)),
                    Number = needToPrintInformationChangeAgreement ? GetAgreementNumber(agreements, ModificationAgreementNames.InformationChangeAgreement) : null
                },
                Auto = new PrntAutoViewModel
                {
                    RegNumber = auto.RegistrationNumber,
                    OriginalKeysAmount = auto.OriginalKeysAmount.ToString(),
                },
                Insurant = new PrntInsurantViewModel
                {
                    LastName = insurant.LastName,
                    Name = insurant.Name,
                    MiddleName = insurant.MiddleName
                },
                TsIdentityCard = new PrntTsIdentityCardViewModel
                {
                    CardTypeShortName = tsIdentityCard.TsIdentityCardType.Name,
                    Series = tsIdentityCard.Series,
                    Number = tsIdentityCard.Number,
                    DateOfIssued = tsIdentityCard.DateOfIssued.GetValueOrDefault()
                },
                Drivers = drivers.Select(d => new PrntKaskoAdditionalAgreementDriverViewModel
                {
                    FullName = d.Subject.IndividualEntity.Person.GetFullName(),
                    DateOfBirth = d.Subject.IndividualEntity.Person.DateOfBirth.ToString(),
                    DrivingExperienceDateStart = d.DrivingExperiences.Last()?.DrivingExperienceDateStart.ToString(),
                    SexCode = d.Subject.IndividualEntity.Person.SexCode,
                    IsMaried = d.Subject.IndividualEntity.Person.IsMaried,
                    HasChildren = d.Subject.IndividualEntity.Person.HasChildren,
                }).ToList(),
                Modifications = modifications.Where(x => _informationChanges.Contains(x.ModificationListForKaskoCode)).Select(m => new PrntModificationViewModel
                {
                    ChangeName = m.ChangeName,
                    NewValue = GetNewValue(deal, m)
                }).ToList()
            };

            return agreement;
        }

        private string ModifyPath(string changePath)
        {
            var replaces = new Dictionary<string, string>()
            {
                { "Auto.", "InsuranceObjects[0].Auto." },
                { ".AutoEngineTypeCode", ".AutoEngineType.Name" },
                { "Owner.", "InsuranceObjects[0].Owners[0]." }
            };

            var sb = new StringBuilder(changePath);

            foreach (var change in replaces)
            {
                sb.Replace(change.Key, change.Value);
            }

            return sb.ToString();
        }

        private int GetAgreementNumber(List<KaskoModificationsAgreementsInBasket> agreements, string agreementName)
        {
            var filteredByName = agreements.Where(a => a.AgreementName == agreementName);
            var last = filteredByName.Select(a => a.AgreementNumber).Max();

            return last;
        }

        private string GetNewValue(Deal deal, KaskoModificationsInBasket modification)
        {
            if (modification.ModificationListForKaskoCode == 26 && modification.ChangePath == "Driver.Subject.IndividualEntity.Person.LastName")
            {
                var driversNames = deal.AutoDeal.Drivers.Select(d => d.Subject.IndividualEntity.Person.GetFullName()).ToList();
                return string.Join(", ", driversNames);
            }

            if (modification.ModificationListForKaskoCode == 35)
            {
                var identityDocument = modification.ChangePath.Contains(nameof(deal.Insurant)) ? 
                    deal.Insurant.IdentityDocument : deal.GetOwner().IdentityDocument;
                return $"Серия: {identityDocument?.Series} №: {identityDocument?.Number} дата выдачи: {identityDocument?.DateIssue?.ToString("dd.MM.yyyy")}";
            }

            if (modification.ModificationListForKaskoCode == 37)
            {
                var tsIdentityCard = deal.AutoDeal.TsIdentityCard;
                return $"Серия: {tsIdentityCard?.Series} №: {tsIdentityCard?.Number}{(tsIdentityCard?.DateOfIssued != null ? $" дата выдачи: {tsIdentityCard.DateOfIssued.Value.ToString("dd.MM.yyyy")}" : string.Empty)}";
            }

            return _pathManager.GetValueByPath(deal, ModifyPath(modification.ChangePath)).ToString();
        }

        public PrntKaskoModificationStatementViewModel GetKaskoModificationStatementViewModel(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            var insurant = deal.GetInsurantPerson();

            var statement = new PrntKaskoModificationStatementViewModel
            {
                FullName = insurant.GetFullName(),
                SexCode = insurant.SexCode,
                PolicyNumber = deal.PolicyNumber,
                DateSign = deal.DateSign,
                IsPreview = !_notPreviewStatusTypes.Contains(deal.DealStatusCode),
            };

            return statement;
        }
    }
}