using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using FamilyTreeAPI.Models;
using FamilyTreeAPI.Entities;
using FamilyTreeAPI.Interface;
using DocumentFormat.OpenXml.Drawing.Diagrams;
using Microsoft.AspNetCore.Http;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Wordprocessing;

namespace FamilyTreeAPI.Repository;

/* password = cGFzc3dvcmQ=
 * 
 INSERT INTO public.staff(
	firstname, lastname, email, phone, stype, srole, spassword, sactive)
	VALUES ( 'kham', 'vilaythong', 'kham.vilaythong', '009', 1, 2, 'cGFzc3dvcmQ=', true);
 */
public class StaffRepository : IStaff
{
    private readonly FamilyTreeDBContext _context;
    private readonly IHttpContextAccessor _httpContext;
    
 
    public StaffRepository(FamilyTreeDBContext context, IHttpContextAccessor httpContext)
    {
        _context = context;
        _httpContext = httpContext;
    }

    private StaffDto FillDto(staff model)
    {
        StaffDto dto = new StaffDto();
        dto.Firstname = model.Firstname;
        dto.Lastname = model.Lastname;
        dto.Type = model.Stype;
        dto.Phone = model.Phone;
        dto.Active = model.Sactive ?? false;
        dto.Email = model.Email;
        /*
        dto.AddedOn = model.AddedOn;
        
        dto.RoleType = model.RoleType;
                    
        */
        dto.RoleType = model.Srole;
        dto.Id = model.Id;            
        return dto;
    }
    private staff FillModel(staff model, StaffDto dto)
    {
        if (!string.IsNullOrEmpty(dto.Firstname))
            model.Firstname = dto.Firstname.Trim();
        if (!string.IsNullOrEmpty(dto.Lastname))
            model.Lastname = dto.Lastname.Trim();
        if (!string.IsNullOrEmpty(dto.Phone))
            model.Phone = dto.Phone.Trim();
       
        if (dto.Id > 0)
            model.Id = dto.Id;
        
        if (!string.IsNullOrEmpty(dto.Password))
        {
                string password = dto.Password.Trim();
                model.Spassword = Ultils.Base64Encode(password);
        }
       
       model.Email = dto.Email;
       model.Srole = dto.RoleType;
       model.Sactive = dto.Active;
        return model;
    }


    public async Task<ResultModel<Dictionary<int,StaffDto>>> GetDicStaffs()
    {
        Dictionary<int,StaffDto> dlist = new();
        int statuscode = 0;
        string error = "";
        StaffDto item;
        staff model;
        try
        {
            var list = await _context.staff.ToListAsync();
            for (int i = 0; i< list.Count; i++)
            {
                model = list[i];
                item = FillDto(model);
                dlist.Add(item.Id, item);
            }
             statuscode = 1;
            //list.Sort((x, y) => x.Code.CompareTo(y.Code));
        }
        catch (Exception ex)
        {
            
            error = ex.ToString();
            statuscode = -1;
            
        }
        return new ResultModel<Dictionary<int,StaffDto>>()
        {
            Data = dlist,
            StatusCode = statuscode,
            Message = error
        };
    }

    public async Task<ResultModel<List<StaffDto> >> GetStaff(StaffCriteria criteria)
    { 
        List<StaffDto> list = new();
        int statuscode = 0;
        string error = "";
        try
        {
            list = await _context.LoadStaffAsync(criteria);           
            statuscode = 1;
            //list.Sort((x, y) => x.Code.CompareTo(y.Code));
        }
        catch (Exception ex)
        {
           
            error = ex.ToString();
            statuscode = -1;
            
        }
        return new ResultModel<List<StaffDto>>()
        {
            Data = list,
            StatusCode = statuscode,
            Message = error
        };
    }

    public async Task<ResultModel<StaffDto>> GetStaffById(int id)
    {
        int statuscode = 0;
        string error = "";
        StaffDto dto = new StaffDto();
        try
        {
            var item = await _context.staff.FindAsync(id);
            if (item == null)
            {
                statuscode = -1;
            }
            else
            {
                dto = FillDto(item);
                statuscode = 1;
            }
        }
        catch(Exception ex)
        {
            error = ex.ToString();
            statuscode = -1;
            
        }
        return new ResultModel<StaffDto>()
        {
            Data = dto,
            StatusCode = statuscode,
            Message = error
        };
    }
    private string GetDateTimeNow()
    {
        return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }
    public async Task<ResultModel<int>> ResetPassword(ResetPassDto item)
    {
        int result = -1;
        int statuscode = 0;
        string error = "";
        try
        {
            staff? model1 = await _context.staff.FindAsync(item.Id);
            if (model1 != null)
            {
                if (!string.IsNullOrEmpty(item.Password))
                {
                    string password = item.Password.Trim();
                    model1.Spassword = Ultils.Base64Encode(password);
                }
               
                //   model.LastModified = DateTime.Now;
                //   model.LastModifiedId = loginName;
                var successid = await _context.SaveChangesAsync();
                result = item.Id;
            }
            statuscode = 1;
        }
        catch (Exception ex)
        {
            statuscode = -1;
            error = ex.ToString();
        }
        return new ResultModel<int>()
        {
            Data = result,
			StatusCode = statuscode,
			Message = error
        };
    }
    public async Task<ResultModel<int>> SaveStaff(StaffDto item)
    {
        int result = default(int);
        int statuscode = 0;
        string error = "";
       
        HttpContext? httpContext = _httpContext.HttpContext;
        string loginName = "";
        if (httpContext != null)
        {
            UserDto? user = (UserDto?)httpContext.Items["User"];
            if (user != null)
                loginName = user.FirstName + " " + user.LastName;
        }

        try 
        {
            if (item.Id < 1)
            {
                bool already = await CheckLoginAlready(item.Email.Trim());
                if (already)
                {
                    return new ResultModel<int>()
                    {
                        Data = 0,
                        StatusCode = 0,
                        Message = "user name already exist in Database"
                    };
                }
            }
            
            staff model;
            if (item.Id < 1)
            {
                model = new();
                model = FillModel(model, item);
               
               // model.Active = true;
               // model.AddedBy = loginName;
               // model.AddedOn = DateTime.Now;
                _context.staff.Add(model);
                await _context.SaveChangesAsync();
                result = model.Id;
            }
            else 
            {
               staff? model1 = await _context.staff.FindAsync(item.Id);
                model1 = FillModel(model1, item);
                //   model.LastModified = DateTime.Now;
                //   model.LastModifiedId = loginName;
                var successid = await _context.SaveChangesAsync();
                result = item.Id;
            }
            
            
            statuscode = 1;

        }
			catch (Exception ex)
			{
				error = ex.ToString();
				statuscode = -1;
				
			}
			//var dto = await Task.Run(() => result);
			return new ResultModel<int>()
			{
				Data = result,
				StatusCode = statuscode,
				Message = error
        };
    }
    private async Task<bool> CheckLoginAlready(string login)
    {
        bool result = false;
        var model = await _context.staff.Where(x => x.Email == login).ToListAsync();
        if (model.Count > 0)
            result = true;
        return result;
    }
    public async Task<ResultModel<int>> SaveStaffNew(StaffDto item)
    {
        int result = default(int);
        int statuscode = 0;
        string error = "";
        
        try
        {
            if (item.Id < 1)
            {
                bool already = await CheckLoginAlready(item.Email.Trim());
                if (already)
                {
                    return new ResultModel<int>()
                    {
                        Data = 0,
                        StatusCode = 0,
                        Message = "user name already exist in db"
                    };
                }
            }
            staff model;
            if (item.Id < 1)
            {
                model = new();
                model = FillModel(model, item);
             //   model.AddedOn = DateTime.Now;
               
            //    model.Active = true;
                _context.staff.Add(model);
            }
            else
            {
                model = await _context.staff.FindAsync(item.Id);
                model = FillModel(model, item);
            }
            var successid = await _context.SaveChangesAsync();
           
            result = 1;
            statuscode = 1;

        }
        catch (Exception ex)
        {
            error = ex.ToString();
            statuscode = -1;
            
        }
        //var dto = await Task.Run(() => result);
        return new ResultModel<int>()
        {
            Data = result,
            StatusCode = statuscode,
            Message = error
        };
    }
  

 

    public async Task<ResultModel<int>> Delete(int id)
    {
        int result = 1;
        int statuscode = 0;
        string error = "";
        try
        {
            staff model;
            model = await _context.staff.FindAsync(id);
          //  if (model != null)
           //     model.Active = false;
                   
            var successCount = await _context.SaveChangesAsync();                
            statuscode = 1;
            result = 1;
        }
        catch (Exception ex)
        {
            error = ex.ToString();
            statuscode = -1;
           
        }
        //var dto = await Task.Run(() => result);
        return new ResultModel<int>()
        {
            Data = result,
            StatusCode = statuscode,
            Message = error
        };
    }
   

}
