using MediatR;
using Microsoft.EntityFrameworkCore;
using Workflow.Domain.Entities;
using Workflow.Domain.Enums;
using Workflow.Domain.Exceptions;
using Workflow.Infrastructure.Persistence;

namespace Workflow.Application.Features.WorkflowInstances.Commands;

public record StartWorkflowInstanceCommand(
    string DefinitionCode,
    string Title,
    string? Variables
) : IRequest<Guid>;

public class StartWorkflowInstanceCommandHandler(WorkflowDbContext db)
    : IRequestHandler<StartWorkflowInstanceCommand, Guid>
{
    public async Task<Guid> Handle(StartWorkflowInstanceCommand request, CancellationToken cancellationToken)
    {
        var definition = await db.WorkflowDefinitions
            .Include(d => d.Nodes)
            .FirstOrDefaultAsync(d => d.Code == request.DefinitionCode, cancellationToken)
            ?? throw new NotFoundException($"Workflow definition with code '{request.DefinitionCode}' not found.");

        if (!definition.IsEnabled)
        {
            throw new BusinessException($"Workflow definition '{request.DefinitionCode}' is disabled.");
        }

        var instanceId = Guid.NewGuid();
        var instance = new WorkflowInstance
        {
            Id = instanceId,
            DefinitionId = definition.Id,
            Title = request.Title,
            Status = InstanceStatus.Running,
            Variables = request.Variables,
            InitiatorId = Guid.Empty // Will be set by audit context in real usage
        };

        db.WorkflowInstances.Add(instance);

        // Find the start node and create an initial token
        var startNode = definition.Nodes.FirstOrDefault(n => n.NodeType == NodeType.Start);
        if (startNode is not null)
        {
            var token = new WorkflowToken
            {
                Id = Guid.NewGuid(),
                InstanceId = instanceId,
                NodeId = startNode.Id,
                Status = TokenStatus.Active
            };
            db.WorkflowTokens.Add(token);
        }

        await db.SaveChangesAsync(cancellationToken);

        return instanceId;
    }
}
