using System.Text.Json;
using System.Text.Json.Serialization;
using e_suite.API.Common.repository;
using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Tables.Domain;
using e_suite.Database.Core.Tables.UserManager;
using e_suite.Workflow.Core;
using e_suite.Workflow.Core.Extensions;

namespace e_suite.Modules.WorkflowTemplatesManager.Repository;

public class WorkflowConverter : IWorkflowConverter
{
    private readonly IDomainRepository _domainRepository;
    private readonly IRoleManagerRepository _roleManagerRepository;
    private readonly IUserManagerRepository _userManagerRepository;

    private readonly JsonSerializerOptions _jsonSerializerOptions;

    public WorkflowConverter(IDomainRepository domainRepository, IRoleManagerRepository roleManagerRepository, IUserManagerRepository userManagerRepository)
    {
        _domainRepository = domainRepository;
        _roleManagerRepository = roleManagerRepository;
        _userManagerRepository = userManagerRepository;


        _jsonSerializerOptions = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true
        };

        _jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        _jsonSerializerOptions.Converters.Add(new GeneralIdRefConverter<Role>(id => _roleManagerRepository.GetRoleById(id)));
        _jsonSerializerOptions.Converters.Add(new GeneralIdRefConverter<User>(id => _userManagerRepository.GetUserById(id)));
    }

    public Workflow.Core.WorkflowVersion DeserialiseFromDatabase(e_suite.Database.Core.Tables.Workflow.WorkflowVersion dbVersion)
    {
        var runtime = new Workflow.Core.WorkflowVersion
        {
            Id = dbVersion.Id,
            Guid = dbVersion.Guid,
            Version = dbVersion.Version,
            ActivityNameTemplate = dbVersion.ActivityNameTemplate,
            Description = dbVersion.Description,
            Domain = dbVersion.Domain.ToGeneralIdRef()!,
            Template = new WorkflowTemplate
            {
                Name = "Need to fix",
                Id = 1,
                Guid = Guid.Empty
            } // however you load templates
        };

        foreach (var def in dbVersion.Tasks)
        {
            var task = def.ToTask(_jsonSerializerOptions);
            runtime.Tasks.Add(task);
        }

        return runtime;
    }
    
    public async Task<e_suite.Database.Core.Tables.Workflow.WorkflowVersion> SerialiseToDatabase(Workflow.Core.WorkflowVersion runtime, e_suite.Database.Core.Tables.Workflow.WorkflowVersion? dbObject = null, CancellationToken cancellationToken = default)
    {
        if (runtime is null)
            throw new NullReferenceException();
        
        var domain = await _domainRepository.GetDomainById(runtime.Domain, cancellationToken);
        if (domain is null)
            throw new Exception($"Domain with id {runtime.Domain} not found.");

        var dbVersion = dbObject ?? new e_suite.Database.Core.Tables.Workflow.WorkflowVersion();

        if (dbObject == null)
        {
            dbVersion.Id = runtime.Id;
            dbVersion.Guid = runtime.Guid;
        }
        else
        {
            //note cannot move a version from one workflow to another, that requires a new version.
            //todo make sure that the Workflow is populated here.
            //dbVersion.Workflow = runtime.Template.ToGeneralIdRef()
        }

        dbVersion.Version = runtime.Version; //todo make sure that the version number get incremented somewhere logical.
        dbVersion.ActivityNameTemplate = runtime.ActivityNameTemplate;
        dbVersion.Description = runtime.Description;
        dbVersion.DomainId = domain.Id;
        dbVersion.Tasks = runtime.Tasks
            .Select(t => t.ToDefinition())
            .ToList();

        return dbVersion;
    }
}