using Common.Contracts.Infrastructure;
using Common.Dtos.Verification;
using Common.Enums;
using Common.Models.Auth;
using Hushian.Application.Contracts.Persistence;
using Hushian.Application.Models;
using Common.Validation;
using Hushian.Domain.Entites;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using Hushian.Application.Models.Message;
using Microsoft.Extensions.Options;

namespace Hushian.Application.Services
{
   public class VerificationService
    {
        private readonly JwtSettings _jwtSettings;
        private readonly IGenericRepository<VerificationCode> _VerificationCodeRepository;
        private readonly IGenericRepository<Company> _CompanyRepository;
        private readonly IGenericRepository<Exper> _ExperRepository;
        private readonly IMessageSender _messageSender;
        private readonly IGenericRepository<User> _UserRepository;

        public VerificationService(IGenericRepository<VerificationCode> verificationCodeRepository
            , IMessageSender messageSender
            , IGenericRepository<User> userRepository
            , IGenericRepository<Company> companyRepository
            , IGenericRepository<Exper> experRepository
            , IOptions<JwtSettings> jwtSettings)
        {
            _VerificationCodeRepository = verificationCodeRepository;
            _messageSender = messageSender;
            _UserRepository = userRepository;
            _CompanyRepository = companyRepository;
            _ExperRepository = experRepository;
            _jwtSettings = jwtSettings.Value;
        }

        public async Task<int> GenerateCodeForLoginUser(string Mobile)
        {
            string Code = await GenerateCode();
        var response=  await  _VerificationCodeRepository.ADD
                (new Identity.Models.VerificationCode(VerificationCodeType.Login, Code, Mobile));
            await _messageSender.SendMessageVerification(Mobile, Code);
            return response.ID;
        }
        public async Task<int> GenerateCodeByPhoneNumberConfirmed(string Mobile)
        {
            string Code = await GenerateCode();
            var response = await _VerificationCodeRepository.ADD
                    (new Identity.Models.VerificationCode(VerificationCodeType.PhoneNumberConfirmed, Code, Mobile));
            await _messageSender.SendMessageVerification(Mobile, Code);
            return response.ID;
        }
        public async Task<int> GenerateCodeByForgetPassword(string Mobile)
        {
            string Code = await GenerateCode();
            var response = await _VerificationCodeRepository.ADD
                    (new Identity.Models.VerificationCode(VerificationCodeType.ForgetPassword, Code, Mobile));
            await _messageSender.SendMessageVerification(Mobile, Code);
            return response.ID;
        }
        public async Task<ResponseBase<AuthResponse>> VerificationCode(ConfirmedCodeDto model)
        {
            var response = new ResponseBase<AuthResponse>();
           var resultConf=await _VerificationCodeRepository.Get()
                .FirstOrDefaultAsync(w => w.ID == model.Id && w.Code == model.code && w.Type == model.codeType);
            if (resultConf!=null)
            {
                if (resultConf.Type == VerificationCodeType.Login)
                {
                    var User= await _UserRepository.Get().FirstOrDefaultAsync(w => w.Mobile == resultConf.Mobile);
                    if (User!=null)
                    {
                        response.Success = true;
                        response.Value = new AuthResponse()
                        {
                            Fullname = User.FullName,
                            Id = User.ID,
                            MobileOrUserName = User.Mobile,
                            Role="User",
                            Token = new JwtSecurityTokenHandler().WriteToken(_jwtSettings.GenerateToken(User.Mobile, User.ID, "User"))
                        };
                    }
                    else
                    {
                        response.Errors.Add("کاربری یافت نشد");
                    } 
                }
                else if (resultConf.Type == VerificationCodeType.ForgetPassword)
                {
                    List<string> errors = new();
                    if (model.value.CheckLawPassword(ref errors)) 
                        response.Errors.AddRange(errors);
                    else
                    {
                        if (resultConf.Mobile.StartsWith("09"))
                        {
                            var anyCompany = await _CompanyRepository.Get().FirstOrDefaultAsync(w => w.Mobile == resultConf.Mobile);
                            anyCompany.Password = model.value.GetHash();
                            anyCompany.Verified = true;
                            if (await _CompanyRepository.UPDATEBool(anyCompany))
                            {
                                response.Success = true;
                                response.Value = new AuthResponse();
                            }
                            else
                            {
                                response.Errors.Add("خطای سیستمی در احراز");
                            }
                        }
                        else
                        {
                           var anyexper=await _ExperRepository.Get().FirstOrDefaultAsync(w => w.UserName == resultConf.Mobile);
                            anyexper.Password = model.value.GetHash();
                            if (await _ExperRepository.UPDATEBool(anyexper))
                            {
                                response.Success = true;
                                response.Value = new AuthResponse();
                            }
                            else
                            {
                                response.Errors.Add("خطای سیستمی در احراز");
                            }
                        }
                       
                    }
                }
                else if (resultConf.Type == VerificationCodeType.PhoneNumberConfirmed)
                {
                  var anyCompany=await  _CompanyRepository.Get().FirstOrDefaultAsync(w => w.Mobile == resultConf.Mobile && !w.Verified);
                    if (anyCompany!=null)
                    {
                        anyCompany.Verified = true;
                       if(await _CompanyRepository.UPDATEBool(anyCompany))
                        {
                            response.Success = true;
                            response.Value = new AuthResponse()
                            {
                                Fullname = anyCompany.FullName,
                                Id = anyCompany.ID,
                                Role = "Company",
                                img = anyCompany.logo,
                                MobileOrUserName = anyCompany.Mobile,
                                Token = new JwtSecurityTokenHandler().WriteToken(_jwtSettings.GenerateToken(anyCompany.Mobile, anyCompany.ID, "Company"))
                            };
                        }
                        else
                        {
                            response.Errors.Add("خطای سیستمی در احراز");
                        }
                    }
                }
                else
                {
                    response.Errors.Add("احراز صحیح نمی باشد");
                }

               await _VerificationCodeRepository.DELETE(resultConf);
            }
            else
            {
                response.Errors.Add("احراز یافت نشد");
            }

            return response;



        }
        public async Task<bool> ReSendCode(int ID)
        {
            var model=await _VerificationCodeRepository.Get().FirstOrDefaultAsync(f=>f.ID==ID);
            if (model==null)
            {
                return false;
            }
            else
            {
              return  await _messageSender.SendMessageVerification(model.Mobile, model.Code);
            }
        }
        private async Task<string> GenerateCode()
        {
            int Code = Random.Shared.Next(1000, 9000);
            while (await _VerificationCodeRepository.Get().AnyAsync(w => w.Code == Code.ToString()))
                Code = Random.Shared.Next(1000, 9000);

            return Code.ToString();
        }
    }
}
