using DocumentFormat.OpenXml.Spreadsheet;
using FamilyTreeAPI.Entities;
using FamilyTreeAPI.Interface;
using FamilyTreeAPI.Models;
using SpreadsheetLight;

namespace FamilyTreeAPI.Repository;

public class ImportPersonRepository
{
    enum enumIdx
    {
        Id = 1,
        FirstName,
        LastName,
        Email,
        Phone,
        Image,
        Sex,
        Address,
        Alive,
        Dob,
        FatherId,
        MotherId,
        
    }
    private FamilyTreeDBContext _context;
    private IConfiguration _config;
    private IHttpContextAccessor _httpContext;
    private IRelationShipd _relationship;
    public ImportPersonRepository(IConfiguration config, FamilyTreeDBContext context,
        IRelationShipd relationship,
        IHttpContextAccessor httpContext)
    {
        _context = context;
        _relationship = relationship;
        _config = config;
        _httpContext = httpContext;
    }
    public async Task<string> GetImageAsBase64String(string imagePath)
    {
        try
        {
            // Read the image file into a byte array
            //byte[] imageBytes = File.ReadAllBytes(imagePath);
            byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
            // Convert the byte array to a Base64 string
            string base64String = Convert.ToBase64String(imageBytes);

            return base64String;
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine($"Error: The file at '{imagePath}' was not found.");
            return null;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"An error occurred: {ex.Message}");
            return null;
        }
    }

    public async Task<ResultModel<string>> DownloadFile(DownloadFileCriteria criteria)
    {
        int statusCode = -1;
        string result = "";
        string error = "";
        try
        {

           
            string imagePath = _config.GetValue<string>("AppSettings:ImageFolder");
            string imageUrl = System.IO.Path.Combine(imagePath, criteria.FileName);
            if (System.IO.File.Exists(imageUrl))
            {
                result = await this.GetImageAsBase64String(imageUrl);
                statusCode = 1;
            }
            else
            {
                error = "error filename " + criteria.FileName + " can not find in this folder:" + imagePath;
                statusCode = -1;
            }
        }
        catch (Exception ex)
        {
            statusCode = -1;
            error = ex.Message;
        }

        return new ResultModel<string>
            { 
                Data = result,
              StatusCode = statusCode, 
              Message = error 
        };

        
    }
    public async Task<List<CodeDto<string>>> ImportPerson(MemoryStream fileStream, string sheetName)
    {
        Dictionary<string, ImportRelation> relationDic = new();
        int id;
        string keypair = ""; //father and mother key
        List<CodeDto<string>> output = new();
        Dictionary<int,MappingFatherMother> updateperson = new();
        CodeDto<string> colums;
        List<int> ids = new();
        Person person;
        Person? uperson;
        ImportRelation iRelation;
        MappingFatherMother mitem,faitem,moitem;
        int fid, mid;
     //   MemoryStream msFirstPass = new MemoryStream();
        SLDocument sl = new SLDocument(fileStream, sheetName);
        // There is no way that I can see to get the Rows
        SLWorksheetStatistics stats = sl.GetWorksheetStatistics();
        for (int row = 2; row <= stats.NumberOfRows; row++)
        {
            person = new Person();
            mitem = new();
            id = sl.GetCellValueAsInt32(row, (int) enumIdx.Id);
            mitem.IId = id;
            person.FirstName = sl.GetCellValueAsString(row, (int) enumIdx.FirstName);
            person.LastName = sl.GetCellValueAsString(row, (int) enumIdx.LastName);
            person.Email = sl.GetCellValueAsString(row, (int) enumIdx.Email);
            person.Phone = sl.GetCellValueAsString(row, (int) enumIdx.Phone);
            person.Image = sl.GetCellValueAsString(row, (int) enumIdx.Image);
            person.Alive  = sl.GetCellValueAsBoolean(row, (int) enumIdx.Alive);
            person.dob = sl.GetCellValueAsDateTime(row, (int) enumIdx.Dob);
            person.Sex = sl.GetCellValueAsString(row, (int) enumIdx.Sex);
            person.Address = sl.GetCellValueAsString(row, (int) enumIdx.Address);
            mitem.IFatherId = sl.GetCellValueAsInt32(row, (int) enumIdx.FatherId);
            mitem.IMotherId = sl.GetCellValueAsInt32(row, (int) enumIdx.MotherId);
            _context.Persons.Add(person);
            _context.SaveChanges();
            mitem.TId = person.Id;
            ids.Add(id);
            updateperson.Add(mitem.IId, mitem);
            colums = new();
            colums.Code = $"{mitem.IId} {mitem.IFatherId} {mitem.IMotherId}";
            colums.Description = $"{mitem.TId} {mitem.TFatherId} {mitem.TMotherId}";
            output.Add(colums);
            
        }

        for (int i = 0; i < ids.Count; i++)
        {
            id = ids[i];
            mitem = updateperson[id];
            fid = mitem.IFatherId;
            if (updateperson.ContainsKey(fid))
            {
                faitem = updateperson[fid];
                mitem.TFatherId = faitem.TId;
            }
            mid = mitem.IMotherId;
            if (updateperson.ContainsKey(mid))
            {
                moitem = updateperson[mid];
                mitem.TMotherId = moitem.TId;
            }

            uperson = await _context.Persons.FindAsync(mitem.TId);
            if (uperson == null) continue;
            uperson.FatherId = mitem.TFatherId;
            uperson.MotherId = mitem.TMotherId;
            if (mitem.TFatherId > 0 && mitem.TMotherId > 0)
            {
                keypair = mitem.TFatherId + "," + mitem.TMotherId;
                if (!relationDic.ContainsKey(keypair))
                {
                    iRelation = new();
                    iRelation.FatherId = mitem.TFatherId;
                    iRelation.MotherId = mitem.TMotherId;
                    relationDic.Add(keypair, iRelation);
                }
            }
            await _context.SaveChangesAsync();

        }
        //finally add relation ship table
        RelationShip model;
        foreach (KeyValuePair<string, ImportRelation> item in relationDic)
        {
            model = new RelationShip();
            model.PersonId = item.Value.FatherId;
            model.RelatePersonId = item.Value.MotherId;
            _context.RelationShips.Add(model);
            _context.SaveChanges();
        }

       
        
        return output;
    }
    
}