using CaseAccountingContracts.BindingModels;
using CaseAccountingContracts.ViewModels;
using CaseAccountingDataModels.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CaseAccountingDataBaseImplement.Models
{
    public class Lawyer : ILawyerModel
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; } = string.Empty;

        [Required]
        public string Surname { get; set; } = string.Empty;

        [Required]
        public string Patronymic { get; set; } = string.Empty;

        [Required]
        public int Experience { get; set; }

        public int? SpecializationId { get; set; }
        public virtual Specialization? Specialization { get; set; } = new();

        [Required]
        public int UserId { get; set; }
        public virtual User User { get; set; } = new();

        [ForeignKey("LawyerId")]
        public virtual List<CaseLawyer> CaseLawyers { get; set; } = new();

        private Dictionary<int, ICaseModel>? _cases;

        [NotMapped]
        public Dictionary<int, ICaseModel> Cases
        {
            get 
            {
                if (_cases == null)
                {
                    _cases = CaseLawyers.ToDictionary(
                        x => x.CaseId, x => x.Case as ICaseModel);
                }
                return _cases;
            }
        }

        [ForeignKey("LawyerId")]
        public virtual List<LawyerContract> LawyerContracts { get; set; } = new();

        private Dictionary<int, IContractModel>? _contracts;

        [NotMapped]
        public Dictionary<int, IContractModel> Contracts
        {
            get
            {
                if (_contracts == null)
                {
                    _contracts = LawyerContracts.ToDictionary(
                        x => x.ContractId, x => x.Contract as IContractModel);
                }
                return _contracts;
            }
        }

        public static Lawyer? Create(CaseAccountingDatabase context, LawyerBindingModel? model)
        {
            if (model == null)
            {
                return null;
            }
            return new Lawyer()
            {
                Id = model.Id,
                Name = model.Name,
                Surname = model.Surname,
                Patronymic = model.Patronymic,
                Experience = model.Experience,
                SpecializationId = model.SpecializationId,
                Specialization = context.Specializations.FirstOrDefault(x => model.SpecializationId.HasValue && x.Id == model.SpecializationId),
                UserId = model.UserId,
                User = context.Users.FirstOrDefault(x => x.Id == model.UserId) ?? throw new Exception("User not found"),
                LawyerContracts = model.Contracts.Select(x => new LawyerContract
                {
                    Contract = context.Contracts.First(y => y.Id == x.Key)
                }).ToList()
            };
        }

        public void Update(CaseAccountingDatabase context, LawyerBindingModel? model)
        {
            if (model == null)
            {
                return;
            }
            Name = model.Name;
            Surname = model.Surname;
            Patronymic = model.Patronymic;
            Experience = model.Experience;
            SpecializationId = model.SpecializationId;
            if (model.Cases.Count > 0)
            {
                CaseLawyers = model.Cases.Select(x => new CaseLawyer
                {
                    Case = context.Cases.First(y => y.Id == x.Key)
                }).ToList();
            }
            if (model.Contracts.Count > 0)
            {
                LawyerContracts = model.Contracts.Select(x => new LawyerContract
                {
                    Contract = context.Contracts.First(y => y.Id == x.Key)
                }).ToList();
            }
        }

        public void UpdateContracts(CaseAccountingDatabase context, LawyerBindingModel model)
        {
            var lawyerContracts = context.LawyerContracts
                .Where(x => x.LawyerId == model.Id)
                .ToList();
            if (lawyerContracts != null)
            {
                context.LawyerContracts
                    .RemoveRange(lawyerContracts
                            .Where(x => !model.Contracts
                            .ContainsKey(x.ContractId))
                        );
                context.SaveChanges();
                var lawyer = context.Lawyers
                    .First(x => x.Id == Id);
                foreach (var lc in lawyerContracts)
                {
                    model.Contracts.Remove(lc.ContractId);
                }
                foreach (var lc in model.Contracts)
                {
                    context.LawyerContracts.Add(new LawyerContract
                    {
                        Lawyer = lawyer,
                        Contract = context.Contracts.First(x => x.Id == lc.Key),
                    });
                    context.SaveChanges();
                }
                _contracts = null;
            }
        }

        public void UpdateCases(CaseAccountingDatabase context, LawyerBindingModel model)
        {
            var lawyerCases = context.CaseLawyers
                .Where(x => x.LawyerId == model.Id)
                .ToList();
            if (lawyerCases != null)
            {
                context.CaseLawyers
                    .RemoveRange(lawyerCases
                            .Where(x => !model.Cases
                            .ContainsKey(x.CaseId))
                        );
                context.SaveChanges();
                var lawyer = context.Lawyers
                    .First(x => x.Id == Id);
                foreach (var lc in lawyerCases)
                {
                    model.Cases.Remove(lc.CaseId);
                }
                foreach (var lc in model.Cases)
                {
                    context.CaseLawyers.Add(new CaseLawyer
                    {
                        Lawyer = lawyer,
                        Case = context.Cases.First(x => x.Id == lc.Key),
                    });
                    context.SaveChanges();
                }
                _contracts = null;
            }
        }

        public LawyerViewModel GetViewModel => new()
        {
            Id = Id,
            Name = Name,
            Surname = Surname,
            Patronymic = Patronymic,
            Experience = Experience,
            SpecializationId = SpecializationId,
            UserId = UserId,
            Specialization = Specialization?.Name ?? "Не указан"
        };
    }
}
