SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF OBJECT_ID(N'dbo.StoryIntelligenceConsents', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.StoryIntelligenceConsents
    (
        StoryIntelligenceConsentID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_StoryIntelligenceConsents PRIMARY KEY,
        UserID int NOT NULL,
        UserOnboardingStateID int NOT NULL,
        ProjectID int NOT NULL,
        BookID int NOT NULL,
        ConsentedUtc datetime2 NOT NULL CONSTRAINT DF_StoryIntelligenceConsents_ConsentedUtc DEFAULT SYSUTCDATETIME(),
        ConsentVersion nvarchar(40) NOT NULL CONSTRAINT DF_StoryIntelligenceConsents_ConsentVersion DEFAULT N'Phase20H',
        ConsentText nvarchar(1000) NOT NULL,
        CONSTRAINT FK_StoryIntelligenceConsents_AppUser FOREIGN KEY (UserID) REFERENCES dbo.AppUser(UserID),
        CONSTRAINT FK_StoryIntelligenceConsents_UserOnboardingState FOREIGN KEY (UserOnboardingStateID) REFERENCES dbo.UserOnboardingState(UserOnboardingStateID),
        CONSTRAINT FK_StoryIntelligenceConsents_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_StoryIntelligenceConsents_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID)
    );
END;
GO

IF OBJECT_ID(N'dbo.StoryIntelligenceJobs', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.StoryIntelligenceJobs
    (
        StoryIntelligenceJobID uniqueidentifier NOT NULL CONSTRAINT PK_StoryIntelligenceJobs PRIMARY KEY,
        StoryIntelligenceConsentID int NOT NULL,
        UserID int NOT NULL,
        ProjectID int NOT NULL,
        BookID int NOT NULL,
        Status nvarchar(40) NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_Status DEFAULT N'Pending',
        CreatedUtc datetime2 NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_CreatedUtc DEFAULT SYSUTCDATETIME(),
        StartedUtc datetime2 NULL,
        CompletedUtc datetime2 NULL,
        CancelledUtc datetime2 NULL,
        ProgressPercent int NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_ProgressPercent DEFAULT 0,
        CurrentStage nvarchar(80) NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_CurrentStage DEFAULT N'Pending',
        CurrentMessage nvarchar(400) NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_CurrentMessage DEFAULT N'Story Intelligence is queued.',
        EstimatedRemaining nvarchar(80) NULL,
        ErrorMessage nvarchar(1000) NULL,
        UpdatedUtc datetime2 NOT NULL CONSTRAINT DF_StoryIntelligenceJobs_UpdatedUtc DEFAULT SYSUTCDATETIME(),
        CONSTRAINT FK_StoryIntelligenceJobs_Consent FOREIGN KEY (StoryIntelligenceConsentID) REFERENCES dbo.StoryIntelligenceConsents(StoryIntelligenceConsentID),
        CONSTRAINT FK_StoryIntelligenceJobs_AppUser FOREIGN KEY (UserID) REFERENCES dbo.AppUser(UserID),
        CONSTRAINT FK_StoryIntelligenceJobs_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_StoryIntelligenceJobs_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID),
        CONSTRAINT CK_StoryIntelligenceJobs_Status CHECK (Status IN
        (
            N'Pending', N'Preparing', N'ReadingScenes', N'AnalysingCharacters', N'AnalysingRelationships',
            N'AnalysingLocations', N'AnalysingAssets', N'AnalysingTimeline', N'Finalising',
            N'Completed', N'Cancelled', N'Failed'
        )),
        CONSTRAINT CK_StoryIntelligenceJobs_ProgressPercent CHECK (ProgressPercent >= 0 AND ProgressPercent <= 100)
    );
END;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryIntelligenceJobs_User_Status' AND object_id = OBJECT_ID(N'dbo.StoryIntelligenceJobs'))
    CREATE INDEX IX_StoryIntelligenceJobs_User_Status ON dbo.StoryIntelligenceJobs(UserID, Status, CreatedUtc DESC);
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryIntelligenceJobs_Pending' AND object_id = OBJECT_ID(N'dbo.StoryIntelligenceJobs'))
    CREATE INDEX IX_StoryIntelligenceJobs_Pending ON dbo.StoryIntelligenceJobs(Status, CreatedUtc) INCLUDE (StoryIntelligenceJobID);
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_Get
    @UserID int,
    @JobID uniqueidentifier
AS
BEGIN
    SET NOCOUNT ON;

    SELECT StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
        Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
        CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
    FROM dbo.StoryIntelligenceJobs
    WHERE StoryIntelligenceJobID = @JobID
        AND UserID = @UserID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_CreateWithConsent
    @UserID int,
    @UserOnboardingStateID int,
    @ProjectID int,
    @BookID int,
    @ConsentText nvarchar(1000)
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    IF NOT EXISTS
    (
        SELECT 1
        FROM dbo.UserOnboardingState uos
        INNER JOIN dbo.Books b ON b.BookID = @BookID AND b.ProjectID = @ProjectID AND b.IsArchived = 0
        INNER JOIN dbo.Projects p ON p.ProjectID = @ProjectID AND p.IsArchived = 0
        INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID AND pua.UserID = @UserID AND pua.IsActive = 1
        WHERE uos.UserOnboardingStateID = @UserOnboardingStateID
            AND uos.UserID = @UserID
    )
        RETURN;

    DECLARE @ExistingActiveJobID uniqueidentifier;
    SELECT TOP (1) @ExistingActiveJobID = StoryIntelligenceJobID
    FROM dbo.StoryIntelligenceJobs
    WHERE UserID = @UserID
        AND ProjectID = @ProjectID
        AND BookID = @BookID
        AND Status IN (N'Pending', N'Preparing', N'ReadingScenes', N'AnalysingCharacters', N'AnalysingRelationships',
            N'AnalysingLocations', N'AnalysingAssets', N'AnalysingTimeline', N'Finalising')
    ORDER BY CreatedUtc DESC;

    IF @ExistingActiveJobID IS NOT NULL
    BEGIN
        EXEC dbo.StoryIntelligenceJob_Get @UserID = @UserID, @JobID = @ExistingActiveJobID;
        RETURN;
    END;

    DECLARE @ConsentID int;
    DECLARE @JobID uniqueidentifier = NEWID();

    BEGIN TRANSACTION;

    INSERT dbo.StoryIntelligenceConsents (UserID, UserOnboardingStateID, ProjectID, BookID, ConsentText)
    VALUES (@UserID, @UserOnboardingStateID, @ProjectID, @BookID, @ConsentText);
    SET @ConsentID = CAST(SCOPE_IDENTITY() AS int);

    INSERT dbo.StoryIntelligenceJobs
    (
        StoryIntelligenceJobID, StoryIntelligenceConsentID, UserID, ProjectID, BookID,
        Status, ProgressPercent, CurrentStage, CurrentMessage, EstimatedRemaining
    )
    VALUES
    (
        @JobID, @ConsentID, @UserID, @ProjectID, @BookID,
        N'Pending', 0, N'Pending', N'Story Intelligence is queued.', N'Calculating'
    );

    COMMIT TRANSACTION;

    EXEC dbo.StoryIntelligenceJob_Get @UserID = @UserID, @JobID = @JobID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_GetLatestForUser
    @UserID int
AS
BEGIN
    SET NOCOUNT ON;

    SELECT TOP (1) StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
        Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
        CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
    FROM dbo.StoryIntelligenceJobs
    WHERE UserID = @UserID
    ORDER BY CreatedUtc DESC;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_ClaimNextPending
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    DECLARE @JobID uniqueidentifier;
    SELECT TOP (1) @JobID = StoryIntelligenceJobID
    FROM dbo.StoryIntelligenceJobs WITH (UPDLOCK, READPAST)
    WHERE Status = N'Pending'
    ORDER BY CreatedUtc;

    IF @JobID IS NULL
    BEGIN
        SELECT TOP (0) StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
            Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
            CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
        FROM dbo.StoryIntelligenceJobs;
        RETURN;
    END;

    UPDATE dbo.StoryIntelligenceJobs
    SET Status = N'Preparing',
        StartedUtc = COALESCE(StartedUtc, SYSUTCDATETIME()),
        ProgressPercent = 5,
        CurrentStage = N'Preparing',
        CurrentMessage = N'Preparing manuscript...',
        EstimatedRemaining = N'Calculating',
        UpdatedUtc = SYSUTCDATETIME()
    WHERE StoryIntelligenceJobID = @JobID
        AND Status = N'Pending';

    SELECT j.StoryIntelligenceJobID AS JobID, j.StoryIntelligenceConsentID AS ConsentID, j.UserID, j.ProjectID, j.BookID,
        j.Status, j.CreatedUtc, j.StartedUtc, j.CompletedUtc, j.CancelledUtc, j.ProgressPercent, j.CurrentStage,
        j.CurrentMessage, j.EstimatedRemaining, j.ErrorMessage, j.UpdatedUtc
    FROM dbo.StoryIntelligenceJobs j
    WHERE j.StoryIntelligenceJobID = @JobID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_UpdateProgress
    @JobID uniqueidentifier,
    @Status nvarchar(40),
    @ProgressPercent int,
    @CurrentStage nvarchar(80),
    @CurrentMessage nvarchar(400),
    @EstimatedRemaining nvarchar(80) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.StoryIntelligenceJobs
    SET Status = @Status,
        ProgressPercent = @ProgressPercent,
        CurrentStage = @CurrentStage,
        CurrentMessage = @CurrentMessage,
        EstimatedRemaining = @EstimatedRemaining,
        UpdatedUtc = SYSUTCDATETIME()
    WHERE StoryIntelligenceJobID = @JobID
        AND Status NOT IN (N'Completed', N'Cancelled', N'Failed');

    SELECT StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
        Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
        CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
    FROM dbo.StoryIntelligenceJobs
    WHERE StoryIntelligenceJobID = @JobID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_Complete
    @JobID uniqueidentifier
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.StoryIntelligenceJobs
    SET Status = N'Completed',
        ProgressPercent = 100,
        CurrentStage = N'Completed',
        CurrentMessage = N'Story Intelligence is ready.',
        EstimatedRemaining = N'Complete',
        CompletedUtc = COALESCE(CompletedUtc, SYSUTCDATETIME()),
        UpdatedUtc = SYSUTCDATETIME()
    WHERE StoryIntelligenceJobID = @JobID
        AND Status NOT IN (N'Completed', N'Cancelled', N'Failed');

    SELECT StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
        Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
        CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
    FROM dbo.StoryIntelligenceJobs
    WHERE StoryIntelligenceJobID = @JobID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_Cancel
    @UserID int,
    @JobID uniqueidentifier
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.StoryIntelligenceJobs
    SET Status = N'Cancelled',
        CurrentStage = N'Cancelled',
        CurrentMessage = N'Story Intelligence setup was cancelled.',
        EstimatedRemaining = NULL,
        CancelledUtc = COALESCE(CancelledUtc, SYSUTCDATETIME()),
        UpdatedUtc = SYSUTCDATETIME()
    WHERE StoryIntelligenceJobID = @JobID
        AND UserID = @UserID
        AND Status NOT IN (N'Completed', N'Cancelled', N'Failed');

    EXEC dbo.StoryIntelligenceJob_Get @UserID = @UserID, @JobID = @JobID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceJob_Fail
    @JobID uniqueidentifier,
    @ErrorMessage nvarchar(1000)
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.StoryIntelligenceJobs
    SET Status = N'Failed',
        CurrentStage = N'Failed',
        CurrentMessage = N'Story Intelligence setup could not finish.',
        ErrorMessage = @ErrorMessage,
        EstimatedRemaining = NULL,
        UpdatedUtc = SYSUTCDATETIME()
    WHERE StoryIntelligenceJobID = @JobID
        AND Status NOT IN (N'Completed', N'Cancelled');

    SELECT StoryIntelligenceJobID AS JobID, StoryIntelligenceConsentID AS ConsentID, UserID, ProjectID, BookID,
        Status, CreatedUtc, StartedUtc, CompletedUtc, CancelledUtc, ProgressPercent, CurrentStage,
        CurrentMessage, EstimatedRemaining, ErrorMessage, UpdatedUtc
    FROM dbo.StoryIntelligenceJobs
    WHERE StoryIntelligenceJobID = @JobID;
END;
GO
