using Dapper;
using PlotLine.Models;

namespace PlotLine.Data;

public interface IStoryIntelligenceIllustrationMatchingRepository
{
    Task<IReadOnlyList<StoryIntelligenceCharacterIllustrationAssignment>> ListAssignmentsAsync(int projectId);
    Task<StoryIntelligenceCharacterIllustrationAssignment> UpsertAssignmentAsync(StoryIntelligenceCharacterIllustrationAssignmentSave request);
    Task<StoryIntelligenceIllustrationDemand> UpsertDemandAsync(StoryIntelligenceIllustrationDemandRequest request);
}

public sealed class StoryIntelligenceIllustrationMatchingRepository(ISqlConnectionFactory connectionFactory) : IStoryIntelligenceIllustrationMatchingRepository
{
    public async Task<IReadOnlyList<StoryIntelligenceCharacterIllustrationAssignment>> ListAssignmentsAsync(int projectId)
    {
        using var connection = connectionFactory.CreateConnection();
        var rows = await connection.QueryAsync<StoryIntelligenceCharacterIllustrationAssignment>(
            """
            SELECT
                StoryIntelligenceCharacterIllustrationAssignmentID,
                ProjectID,
                CharacterKey,
                CharacterName,
                IllustrationLibraryItemID,
                StableCode,
                MatchConfidence,
                MatchingScore,
                CAST(NULL AS nvarchar(max)) AS EvidenceJson,
                CAST(NULL AS nvarchar(max)) AS CandidateDiagnosticsJson,
                ReasonChosen,
                ReasonReassigned,
                IsActive,
                CreatedUtc,
                UpdatedUtc,
                AssignmentStatus,
                AssignedUtc,
                LastValidatedUtc,
                EvidenceVersion,
                IsFallback
            FROM dbo.StoryIntelligenceCharacterIllustrationAssignments
            WHERE ProjectID = @ProjectID
                AND IsActive = 1;
            """,
            new { ProjectID = projectId });
        return rows.ToList();
    }

    public async Task<StoryIntelligenceCharacterIllustrationAssignment> UpsertAssignmentAsync(StoryIntelligenceCharacterIllustrationAssignmentSave request)
    {
        using var connection = connectionFactory.CreateConnection();
        return await connection.QuerySingleAsync<StoryIntelligenceCharacterIllustrationAssignment>(
            """
            SET XACT_ABORT ON;

            MERGE dbo.StoryIntelligenceCharacterIllustrationAssignments WITH (HOLDLOCK) AS target
            USING (SELECT @ProjectID AS ProjectID, @CharacterKey AS CharacterKey) AS source
                ON target.ProjectID = source.ProjectID
                AND target.CharacterKey = source.CharacterKey
                AND target.IsActive = 1
            WHEN MATCHED THEN
                UPDATE SET
                    CharacterName = @CharacterName,
                    IllustrationLibraryItemID = @IllustrationLibraryItemID,
                    StableCode = @StableCode,
                    MatchConfidence = @MatchConfidence,
                    MatchingScore = @MatchingScore,
                    EvidenceJson = @EvidenceJson,
                    CandidateDiagnosticsJson = @CandidateDiagnosticsJson,
                    ReasonChosen = @ReasonChosen,
                    ReasonReassigned = @ReasonReassigned,
                    AssignmentStatus = CASE WHEN @IllustrationLibraryItemID IS NULL THEN N'Fallback' ELSE N'Assigned' END,
                    LastValidatedUtc = SYSUTCDATETIME(),
                    EvidenceVersion = N'21K',
                    IsFallback = CASE WHEN @IllustrationLibraryItemID IS NULL THEN 1 ELSE 0 END,
                    UpdatedUtc = SYSUTCDATETIME()
            WHEN NOT MATCHED THEN
                INSERT (ProjectID, CharacterKey, CharacterName, IllustrationLibraryItemID, StableCode, MatchConfidence, MatchingScore, EvidenceJson, CandidateDiagnosticsJson, ReasonChosen, ReasonReassigned, AssignmentStatus, AssignedUtc, LastValidatedUtc, EvidenceVersion, IsFallback)
                VALUES (@ProjectID, @CharacterKey, @CharacterName, @IllustrationLibraryItemID, @StableCode, @MatchConfidence, @MatchingScore, @EvidenceJson, @CandidateDiagnosticsJson, @ReasonChosen, @ReasonReassigned, CASE WHEN @IllustrationLibraryItemID IS NULL THEN N'Fallback' ELSE N'Assigned' END, SYSUTCDATETIME(), SYSUTCDATETIME(), N'21K', CASE WHEN @IllustrationLibraryItemID IS NULL THEN 1 ELSE 0 END);

            SELECT *
            FROM dbo.StoryIntelligenceCharacterIllustrationAssignments
            WHERE ProjectID = @ProjectID
                AND CharacterKey = @CharacterKey
                AND IsActive = 1;
            """,
            request);
    }

    public async Task<StoryIntelligenceIllustrationDemand> UpsertDemandAsync(StoryIntelligenceIllustrationDemandRequest request)
    {
        using var connection = connectionFactory.CreateConnection();
        return await connection.QuerySingleAsync<StoryIntelligenceIllustrationDemand>(
            """
            SET XACT_ABORT ON;

            MERGE dbo.StoryIntelligenceIllustrationDemands WITH (HOLDLOCK) AS target
            USING (SELECT @ProjectID AS ProjectID, @DemandKey AS DemandKey) AS source
                ON ISNULL(target.ProjectID, -1) = ISNULL(source.ProjectID, -1)
                AND target.DemandKey = source.DemandKey
            WHEN MATCHED THEN
                UPDATE SET
                    RequestCount = RequestCount + 1,
                    LastRequestedUtc = SYSUTCDATETIME(),
                    UpdatedUtc = SYSUTCDATETIME()
            WHEN NOT MATCHED THEN
                INSERT (ProjectID, DemandKey, AgeBand, Presentation, HairColour, SkinTone, HairLength, Glasses, FacialHair)
                VALUES (@ProjectID, @DemandKey, @AgeBand, @Presentation, @HairColour, @SkinTone, @HairLength, @Glasses, @FacialHair);

            SELECT *
            FROM dbo.StoryIntelligenceIllustrationDemands
            WHERE ISNULL(ProjectID, -1) = ISNULL(@ProjectID, -1)
                AND DemandKey = @DemandKey;
            """,
            request);
    }
}
