using System.Globalization;

namespace OI.Metrology.Server.Services;

using OI.Metrology.Server.Models;
using OI.Metrology.Shared.DataModels;
using OI.Metrology.Shared.Models.Stateless;
using OI.Metrology.Shared.Services;

public class AttachmentsService : IAttachmentsService
{
    private readonly AppSettings _AppSettings;
    private readonly IMetrologyRepository _MetrologyRepository;

    public AttachmentsService(AppSettings appSettings, IMetrologyRepository metrologyRepository)
    {
        _AppSettings = appSettings;
        _MetrologyRepository = metrologyRepository;
    }

    protected Stream GetAttachmentStream(string? tableName, Guid attachmentId, string filename)
    {
        if (attachmentId.Equals(Guid.Empty))
            throw new Exception("No attachments found");

        if (tableName is null)
            throw new NullReferenceException(nameof(tableName));

        DateTime insertDate = Convert.ToDateTime(_MetrologyRepository.GetAttachmentInsertDateByGUID(tableName, attachmentId));
        string year = insertDate.Year.ToString();
        int weekNum = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(insertDate, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
        string directory = Path.Combine(_AppSettings.AttachmentPath, tableName + "_", year, $"WW{weekNum:00}", attachmentId.ToString());
        if (!Directory.Exists(directory))
            _ = Directory.CreateDirectory(directory);
        string fullPath = Path.Combine(directory, filename);

        // Check to see if file exists in the "New" directory structure, if not change the path back to the old. and check there
        if (!File.Exists(fullPath))
        {
            fullPath = Path.Combine(_AppSettings.AttachmentPath, tableName, attachmentId.ToString(), filename);
        }

        if (!File.Exists(fullPath))
            throw new Exception("File not found");

        return new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    }

    Stream IAttachmentsService.GetAttachmentStreamByTitle(ToolType toolType, bool header, string title, string filename)
    {
        if (toolType is null)
            throw new Exception("Invalid tool type");
        Guid attachmentId;
        string? tableName;
        if (header)
        {
            tableName = toolType.HeaderTableName;
            attachmentId = _MetrologyRepository.GetHeaderAttachmentIDByTitle(toolType.ID, title);
        }
        else
        {
            tableName = toolType.DataTableName;
            attachmentId = _MetrologyRepository.GetDataAttachmentIDByTitle(toolType.ID, title);
        }
        return GetAttachmentStream(tableName, attachmentId, filename);
    }

    Stream IAttachmentsService.GetAttachmentStreamByAttachmentId(ToolType toolType, bool header, Guid attachmentId, string filename)
    {
        if (toolType is null)
            throw new Exception("Invalid tool type");
        string? tableName;
        if (header)
            tableName = toolType.HeaderTableName;
        else
            tableName = toolType.DataTableName;
        return GetAttachmentStream(tableName, attachmentId, filename);
    }

    private void SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, IFormFile uploadedFile)
    {
        if (toolType is null)
            throw new Exception("Invalid tool type");

        using System.Transactions.TransactionScope trans = _MetrologyRepository.StartTransaction();
        Guid attachmentId = Guid.Empty;
        DateTime insertDate = new();
        string? tableName = "";

        if (string.IsNullOrWhiteSpace(dataUniqueId))
        {
            attachmentId = _MetrologyRepository.GetHeaderAttachmentID(toolType.ID, headerId);
            insertDate = Convert.ToDateTime(_MetrologyRepository.GetHeaderInsertDate(toolType.ID, headerId));
            tableName = toolType.HeaderTableName;
        }
        else
        {
            attachmentId = _MetrologyRepository.GetDataAttachmentID(toolType.ID, headerId, dataUniqueId);
            insertDate = Convert.ToDateTime(_MetrologyRepository.GetDataInsertDate(toolType.ID, headerId, dataUniqueId));
            // Get Date for new directory name
            tableName = toolType.DataTableName;
        }
        if (Equals(attachmentId, Guid.Empty))
            throw new Exception("Invalid attachment ID");

        string year = insertDate.Year.ToString();
        int weekNum = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(insertDate, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
        string directory = Path.Combine(_AppSettings.AttachmentPath, $"{tableName}_", year, $"WW{weekNum:00}", attachmentId.ToString());
        if (!Directory.Exists(directory))
            _ = Directory.CreateDirectory(directory);

        string fullPath = Path.Combine(directory, filename);

        using (FileStream fileStream = new(fullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None))
            uploadedFile.CopyTo(fileStream);
        trans.Complete();
    }

    void IAttachmentsService.SaveAttachment(ToolType toolType, long headerId, string dataUniqueId, string filename, object uploadedFile)
    {
        IFormFile formFile = (IFormFile)uploadedFile;
        SaveAttachment(toolType, headerId, dataUniqueId, filename, formFile);
    }

    string? IAttachmentsService.GetProcessDataStandardFormat(IMetrologyRepository metrologyRepository, string attachmentPath, int toolTypeId, long headerId)
    {
        string? result;
        string year;
        int weekNum;
        string directory;
        string checkDirectory;
        List<string> files = new();
        DateTime[] dateTimes = new DateTime[] { DateTime.Now, DateTime.Now.AddDays(-6.66) };
        ToolType toolType = metrologyRepository.GetToolTypeByID(toolTypeId) ?? throw new Exception("Invalid tool type ID");
        foreach (DateTime dateTime in dateTimes)
        {
            year = dateTime.Year.ToString();
            weekNum = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday);
            directory = Path.Combine(_AppSettings.AttachmentPath, $"{toolType.HeaderTableName}_", year, $"WW{weekNum:00}");
            if (!Directory.Exists(directory))
                _ = Directory.CreateDirectory(directory);
            checkDirectory = Path.Combine(directory, headerId.ToString());
            if (!Directory.Exists(checkDirectory))
                continue;
            files.AddRange(Directory.GetFiles(checkDirectory));
            if (files.Count != 0)
                break;
        }
        result = files.Count == 0 ? null : files.First();
        return result;
    }

}