SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF OBJECT_ID(N'dbo.PlotLineTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.PlotLineTypes
    (
        PlotLineTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_PlotLineTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_PlotLineTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_PlotLineTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.PlotLines', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.PlotLines
    (
        PlotLineID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_PlotLines PRIMARY KEY,
        ProjectID int NOT NULL,
        BookID int NULL,
        PlotLineName nvarchar(200) NOT NULL,
        PlotLineTypeID int NOT NULL,
        Description nvarchar(max) NULL,
        ParentPlotLineID int NULL,
        SortOrder int NOT NULL,
        Colour nvarchar(20) NOT NULL CONSTRAINT DF_PlotLines_Colour DEFAULT N'#2f6f63',
        IsMainPlot bit NOT NULL CONSTRAINT DF_PlotLines_IsMainPlot DEFAULT 0,
        IsVisibleOnTimeline bit NOT NULL CONSTRAINT DF_PlotLines_IsVisibleOnTimeline DEFAULT 1,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_PlotLines_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_PlotLines_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_PlotLines_IsArchived DEFAULT 0,
        CONSTRAINT FK_PlotLines_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_PlotLines_Books FOREIGN KEY (BookID) REFERENCES dbo.Books(BookID),
        CONSTRAINT FK_PlotLines_PlotLineTypes FOREIGN KEY (PlotLineTypeID) REFERENCES dbo.PlotLineTypes(PlotLineTypeID),
        CONSTRAINT FK_PlotLines_ParentPlotLines FOREIGN KEY (ParentPlotLineID) REFERENCES dbo.PlotLines(PlotLineID)
    );
END;
GO

IF OBJECT_ID(N'dbo.ThreadTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.ThreadTypes
    (
        ThreadTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ThreadTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_ThreadTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_ThreadTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.ThreadStatuses', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.ThreadStatuses
    (
        ThreadStatusID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ThreadStatuses PRIMARY KEY,
        StatusName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsOpenStatus bit NOT NULL,
        IsResolvedStatus bit NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_ThreadStatuses_IsActive DEFAULT 1,
        CONSTRAINT UQ_ThreadStatuses_StatusName UNIQUE (StatusName)
    );
END;
GO

IF OBJECT_ID(N'dbo.PlotThreads', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.PlotThreads
    (
        PlotThreadID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_PlotThreads PRIMARY KEY,
        PlotLineID int NOT NULL,
        ThreadTitle nvarchar(200) NOT NULL,
        ThreadTypeID int NOT NULL,
        ThreadStatusID int NOT NULL,
        Importance int NOT NULL CONSTRAINT DF_PlotThreads_Importance DEFAULT 5,
        Summary nvarchar(max) NULL,
        IntroducedSceneID int NULL,
        PlannedResolutionSceneID int NULL,
        ActualResolutionSceneID int NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_PlotThreads_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_PlotThreads_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_PlotThreads_IsArchived DEFAULT 0,
        CONSTRAINT FK_PlotThreads_PlotLines FOREIGN KEY (PlotLineID) REFERENCES dbo.PlotLines(PlotLineID),
        CONSTRAINT FK_PlotThreads_ThreadTypes FOREIGN KEY (ThreadTypeID) REFERENCES dbo.ThreadTypes(ThreadTypeID),
        CONSTRAINT FK_PlotThreads_ThreadStatuses FOREIGN KEY (ThreadStatusID) REFERENCES dbo.ThreadStatuses(ThreadStatusID),
        CONSTRAINT FK_PlotThreads_IntroducedScene FOREIGN KEY (IntroducedSceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_PlotThreads_PlannedResolutionScene FOREIGN KEY (PlannedResolutionSceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_PlotThreads_ActualResolutionScene FOREIGN KEY (ActualResolutionSceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT CK_PlotThreads_Importance CHECK (Importance BETWEEN 1 AND 10)
    );
END;
GO

IF OBJECT_ID(N'dbo.ThreadEventTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.ThreadEventTypes
    (
        ThreadEventTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ThreadEventTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        MarkerText nvarchar(20) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_ThreadEventTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_ThreadEventTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.ThreadEvents', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.ThreadEvents
    (
        ThreadEventID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_ThreadEvents PRIMARY KEY,
        PlotThreadID int NOT NULL,
        SceneID int NOT NULL,
        EventTypeID int NOT NULL,
        EventTitle nvarchar(200) NOT NULL,
        EventDescription nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_ThreadEvents_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_ThreadEvents_UpdatedDate DEFAULT SYSUTCDATETIME(),
        CONSTRAINT FK_ThreadEvents_PlotThreads FOREIGN KEY (PlotThreadID) REFERENCES dbo.PlotThreads(PlotThreadID),
        CONSTRAINT FK_ThreadEvents_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_ThreadEvents_ThreadEventTypes FOREIGN KEY (EventTypeID) REFERENCES dbo.ThreadEventTypes(ThreadEventTypeID)
    );
END;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_PlotLines_ProjectID_SortOrder' AND object_id = OBJECT_ID(N'dbo.PlotLines'))
    CREATE INDEX IX_PlotLines_ProjectID_SortOrder ON dbo.PlotLines(ProjectID, IsArchived, IsVisibleOnTimeline, SortOrder);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_PlotThreads_PlotLineID' AND object_id = OBJECT_ID(N'dbo.PlotThreads'))
    CREATE INDEX IX_PlotThreads_PlotLineID ON dbo.PlotThreads(PlotLineID, IsArchived, ThreadStatusID);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_ThreadEvents_SceneID' AND object_id = OBJECT_ID(N'dbo.ThreadEvents'))
    CREATE INDEX IX_ThreadEvents_SceneID ON dbo.ThreadEvents(SceneID, PlotThreadID, EventTypeID);
GO

MERGE dbo.PlotLineTypes AS target
USING (VALUES
    (N'Main Plot', 10), (N'Side Plot', 20), (N'Mystery', 30), (N'Emotional Arc', 40),
    (N'Relationship Arc', 50), (N'Character Arc', 60), (N'Object Trail', 70),
    (N'Investigation', 80), (N'Location Plot', 90), (N'Theme', 100)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder, IsActive) VALUES (source.TypeName, source.SortOrder, 1);
GO

MERGE dbo.ThreadTypes AS target
USING (VALUES
    (N'Question', 10), (N'Clue', 20), (N'Mystery', 30), (N'Suspicion', 40), (N'Promise', 50),
    (N'Threat', 60), (N'Emotional Issue', 70), (N'Relationship Issue', 80), (N'Secret', 90),
    (N'Continuity Item', 100), (N'Payoff Setup', 110)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder, IsActive) VALUES (source.TypeName, source.SortOrder, 1);
GO

MERGE dbo.ThreadStatuses AS target
USING (VALUES
    (N'Planned', 10, 1, 0), (N'Introduced', 20, 1, 0), (N'Developing', 30, 1, 0),
    (N'Dormant', 40, 1, 0), (N'Ready For Payoff', 50, 1, 0),
    (N'Resolved', 60, 0, 1), (N'Abandoned', 70, 0, 1)
) AS source (StatusName, SortOrder, IsOpenStatus, IsResolvedStatus)
ON target.StatusName = source.StatusName
WHEN NOT MATCHED THEN
    INSERT (StatusName, SortOrder, IsOpenStatus, IsResolvedStatus, IsActive)
    VALUES (source.StatusName, source.SortOrder, source.IsOpenStatus, source.IsResolvedStatus, 1);
GO

MERGE dbo.ThreadEventTypes AS target
USING (VALUES
    (N'Introduced', N'I', 10), (N'Mentioned', N'M', 20), (N'Developed', N'D', 30),
    (N'Complicated', N'C', 40), (N'Clue Planted', N'clue', 50), (N'Question Raised', N'?', 60),
    (N'Question Answered', N'A', 70), (N'False Lead', N'F', 80), (N'Revealed', N'Rv', 90),
    (N'Payoff', N'P', 100), (N'Resolved', NCHAR(10003), 110), (N'Contradicted', N'!', 120),
    (N'Retconned', N'Rt', 130), (N'Note', N'N', 140)
) AS source (TypeName, MarkerText, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN
    INSERT (TypeName, MarkerText, SortOrder, IsActive)
    VALUES (source.TypeName, source.MarkerText, source.SortOrder, 1);
GO

CREATE OR ALTER PROCEDURE dbo.PlotLookup_All
AS
BEGIN
    SET NOCOUNT ON;
    SELECT PlotLineTypeID, TypeName, SortOrder, IsActive FROM dbo.PlotLineTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT ThreadTypeID, TypeName, SortOrder, IsActive FROM dbo.ThreadTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT ThreadStatusID, StatusName, SortOrder, IsOpenStatus, IsResolvedStatus, IsActive FROM dbo.ThreadStatuses WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT ThreadEventTypeID, TypeName, MarkerText, SortOrder, IsActive FROM dbo.ThreadEventTypes WHERE IsActive = 1 ORDER BY SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotLine_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT pl.PlotLineID, pl.ProjectID, pl.BookID, b.BookTitle, pl.PlotLineName, pl.PlotLineTypeID,
        plt.TypeName AS PlotLineTypeName, pl.Description, pl.ParentPlotLineID, parent.PlotLineName AS ParentPlotLineName,
        pl.SortOrder, pl.Colour, pl.IsMainPlot, pl.IsVisibleOnTimeline, pl.CreatedDate, pl.UpdatedDate, pl.IsArchived
    FROM dbo.PlotLines pl
    INNER JOIN dbo.PlotLineTypes plt ON plt.PlotLineTypeID = pl.PlotLineTypeID
    LEFT JOIN dbo.Books b ON b.BookID = pl.BookID
    LEFT JOIN dbo.PlotLines parent ON parent.PlotLineID = pl.ParentPlotLineID
    WHERE pl.ProjectID = @ProjectID AND pl.IsArchived = 0
    ORDER BY pl.SortOrder, pl.PlotLineName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotLine_Get
    @PlotLineID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT pl.PlotLineID, pl.ProjectID, pl.BookID, b.BookTitle, pl.PlotLineName, pl.PlotLineTypeID,
        plt.TypeName AS PlotLineTypeName, pl.Description, pl.ParentPlotLineID, parent.PlotLineName AS ParentPlotLineName,
        pl.SortOrder, pl.Colour, pl.IsMainPlot, pl.IsVisibleOnTimeline, pl.CreatedDate, pl.UpdatedDate, pl.IsArchived
    FROM dbo.PlotLines pl
    INNER JOIN dbo.PlotLineTypes plt ON plt.PlotLineTypeID = pl.PlotLineTypeID
    LEFT JOIN dbo.Books b ON b.BookID = pl.BookID
    LEFT JOIN dbo.PlotLines parent ON parent.PlotLineID = pl.ParentPlotLineID
    WHERE pl.PlotLineID = @PlotLineID AND pl.IsArchived = 0;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotLine_Save
    @PlotLineID int = NULL,
    @ProjectID int,
    @BookID int = NULL,
    @PlotLineName nvarchar(200),
    @PlotLineTypeID int,
    @Description nvarchar(max) = NULL,
    @ParentPlotLineID int = NULL,
    @SortOrder int = NULL,
    @Colour nvarchar(20),
    @IsMainPlot bit,
    @IsVisibleOnTimeline bit
AS
BEGIN
    SET NOCOUNT ON;
    IF @PlotLineID IS NULL OR @PlotLineID = 0
    BEGIN
        DECLARE @NextSortOrder int = COALESCE(@SortOrder, ISNULL((SELECT MAX(SortOrder) FROM dbo.PlotLines WHERE ProjectID = @ProjectID), 0) + 10);
        INSERT dbo.PlotLines (ProjectID, BookID, PlotLineName, PlotLineTypeID, Description, ParentPlotLineID, SortOrder, Colour, IsMainPlot, IsVisibleOnTimeline)
        VALUES (@ProjectID, @BookID, @PlotLineName, @PlotLineTypeID, @Description, @ParentPlotLineID, @NextSortOrder, @Colour, @IsMainPlot, @IsVisibleOnTimeline);
        SELECT CAST(SCOPE_IDENTITY() AS int);
        RETURN;
    END;

    UPDATE dbo.PlotLines
    SET BookID = @BookID,
        PlotLineName = @PlotLineName,
        PlotLineTypeID = @PlotLineTypeID,
        Description = @Description,
        ParentPlotLineID = @ParentPlotLineID,
        SortOrder = COALESCE(@SortOrder, SortOrder),
        Colour = @Colour,
        IsMainPlot = @IsMainPlot,
        IsVisibleOnTimeline = @IsVisibleOnTimeline,
        UpdatedDate = SYSUTCDATETIME()
    WHERE PlotLineID = @PlotLineID;

    SELECT @PlotLineID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotLine_Archive
    @PlotLineID int
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.PlotLines SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE PlotLineID = @PlotLineID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotThread_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT pt.PlotThreadID, pt.PlotLineID, pl.ProjectID, pl.PlotLineName, pt.ThreadTitle,
        pt.ThreadTypeID, tt.TypeName AS ThreadTypeName, pt.ThreadStatusID, ts.StatusName AS ThreadStatusName,
        pt.Importance, pt.Summary, pt.IntroducedSceneID, pt.PlannedResolutionSceneID, pt.ActualResolutionSceneID,
        pt.CreatedDate, pt.UpdatedDate, pt.IsArchived
    FROM dbo.PlotThreads pt
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadTypes tt ON tt.ThreadTypeID = pt.ThreadTypeID
    INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
    WHERE pl.ProjectID = @ProjectID AND pl.IsArchived = 0 AND pt.IsArchived = 0
    ORDER BY pl.SortOrder, pt.Importance DESC, pt.ThreadTitle;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotThread_ListByPlotLine
    @PlotLineID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT pt.PlotThreadID, pt.PlotLineID, pl.ProjectID, pl.PlotLineName, pt.ThreadTitle,
        pt.ThreadTypeID, tt.TypeName AS ThreadTypeName, pt.ThreadStatusID, ts.StatusName AS ThreadStatusName,
        pt.Importance, pt.Summary, pt.IntroducedSceneID, pt.PlannedResolutionSceneID, pt.ActualResolutionSceneID,
        pt.CreatedDate, pt.UpdatedDate, pt.IsArchived
    FROM dbo.PlotThreads pt
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadTypes tt ON tt.ThreadTypeID = pt.ThreadTypeID
    INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
    WHERE pt.PlotLineID = @PlotLineID AND pt.IsArchived = 0
    ORDER BY pt.Importance DESC, pt.ThreadTitle;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotThread_Get
    @PlotThreadID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT pt.PlotThreadID, pt.PlotLineID, pl.ProjectID, pl.PlotLineName, pt.ThreadTitle,
        pt.ThreadTypeID, tt.TypeName AS ThreadTypeName, pt.ThreadStatusID, ts.StatusName AS ThreadStatusName,
        pt.Importance, pt.Summary, pt.IntroducedSceneID, pt.PlannedResolutionSceneID, pt.ActualResolutionSceneID,
        pt.CreatedDate, pt.UpdatedDate, pt.IsArchived
    FROM dbo.PlotThreads pt
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadTypes tt ON tt.ThreadTypeID = pt.ThreadTypeID
    INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
    WHERE pt.PlotThreadID = @PlotThreadID AND pt.IsArchived = 0;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotThread_Save
    @PlotThreadID int = NULL,
    @PlotLineID int,
    @ThreadTitle nvarchar(200),
    @ThreadTypeID int,
    @ThreadStatusID int,
    @Importance int,
    @Summary nvarchar(max) = NULL,
    @IntroducedSceneID int = NULL,
    @PlannedResolutionSceneID int = NULL,
    @ActualResolutionSceneID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @PlotThreadID IS NULL OR @PlotThreadID = 0
    BEGIN
        INSERT dbo.PlotThreads (PlotLineID, ThreadTitle, ThreadTypeID, ThreadStatusID, Importance, Summary, IntroducedSceneID, PlannedResolutionSceneID, ActualResolutionSceneID)
        VALUES (@PlotLineID, @ThreadTitle, @ThreadTypeID, @ThreadStatusID, @Importance, @Summary, @IntroducedSceneID, @PlannedResolutionSceneID, @ActualResolutionSceneID);
        SELECT CAST(SCOPE_IDENTITY() AS int);
        RETURN;
    END;

    UPDATE dbo.PlotThreads
    SET PlotLineID = @PlotLineID,
        ThreadTitle = @ThreadTitle,
        ThreadTypeID = @ThreadTypeID,
        ThreadStatusID = @ThreadStatusID,
        Importance = @Importance,
        Summary = @Summary,
        IntroducedSceneID = @IntroducedSceneID,
        PlannedResolutionSceneID = @PlannedResolutionSceneID,
        ActualResolutionSceneID = @ActualResolutionSceneID,
        UpdatedDate = SYSUTCDATETIME()
    WHERE PlotThreadID = @PlotThreadID;

    SELECT @PlotThreadID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.PlotThread_Archive
    @PlotThreadID int
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.PlotThreads SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE PlotThreadID = @PlotThreadID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.ThreadEvent_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT te.ThreadEventID, te.PlotThreadID, pt.ThreadTitle, pt.PlotLineID, pl.PlotLineName, pl.Colour,
        te.SceneID, te.EventTypeID, tet.TypeName AS EventTypeName, tet.MarkerText, te.EventTitle,
        te.EventDescription, te.CreatedDate, te.UpdatedDate
    FROM dbo.ThreadEvents te
    INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
    WHERE te.SceneID = @SceneID AND pt.IsArchived = 0 AND pl.IsArchived = 0
    ORDER BY pl.SortOrder, pt.Importance DESC, te.CreatedDate;
END;
GO

CREATE OR ALTER PROCEDURE dbo.ThreadEvent_ListByPlotThread
    @PlotThreadID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT te.ThreadEventID, te.PlotThreadID, pt.ThreadTitle, pt.PlotLineID, pl.PlotLineName, pl.Colour,
        te.SceneID, te.EventTypeID, tet.TypeName AS EventTypeName, tet.MarkerText, te.EventTitle,
        te.EventDescription, te.CreatedDate, te.UpdatedDate
    FROM dbo.ThreadEvents te
    INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
    WHERE te.PlotThreadID = @PlotThreadID
    ORDER BY te.CreatedDate;
END;
GO

CREATE OR ALTER PROCEDURE dbo.ThreadEvent_Save
    @ThreadEventID int = NULL,
    @PlotThreadID int,
    @SceneID int,
    @EventTypeID int,
    @EventTitle nvarchar(200),
    @EventDescription nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    IF @ThreadEventID IS NULL OR @ThreadEventID = 0
    BEGIN
        INSERT dbo.ThreadEvents (PlotThreadID, SceneID, EventTypeID, EventTitle, EventDescription)
        VALUES (@PlotThreadID, @SceneID, @EventTypeID, @EventTitle, @EventDescription);
        SET @ThreadEventID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.ThreadEvents
        SET PlotThreadID = @PlotThreadID,
            SceneID = @SceneID,
            EventTypeID = @EventTypeID,
            EventTitle = @EventTitle,
            EventDescription = @EventDescription,
            UpdatedDate = SYSUTCDATETIME()
        WHERE ThreadEventID = @ThreadEventID;
    END;

    DECLARE @EventTypeName nvarchar(100);
    SELECT @EventTypeName = TypeName FROM dbo.ThreadEventTypes WHERE ThreadEventTypeID = @EventTypeID;

    IF @EventTypeName = N'Introduced'
    BEGIN
        UPDATE pt
        SET IntroducedSceneID = COALESCE(IntroducedSceneID, @SceneID),
            ThreadStatusID = CASE WHEN ts.StatusName = N'Planned' THEN introduced.ThreadStatusID ELSE pt.ThreadStatusID END,
            UpdatedDate = SYSUTCDATETIME()
        FROM dbo.PlotThreads pt
        INNER JOIN dbo.ThreadStatuses ts ON ts.ThreadStatusID = pt.ThreadStatusID
        CROSS APPLY (SELECT ThreadStatusID FROM dbo.ThreadStatuses WHERE StatusName = N'Introduced') introduced
        WHERE pt.PlotThreadID = @PlotThreadID;
    END;

    IF @EventTypeName IN (N'Resolved', N'Payoff')
    BEGIN
        UPDATE pt
        SET ActualResolutionSceneID = COALESCE(ActualResolutionSceneID, @SceneID),
            ThreadStatusID = CASE WHEN @EventTypeName = N'Resolved' THEN resolved.ThreadStatusID ELSE pt.ThreadStatusID END,
            UpdatedDate = SYSUTCDATETIME()
        FROM dbo.PlotThreads pt
        CROSS APPLY (SELECT ThreadStatusID FROM dbo.ThreadStatuses WHERE StatusName = N'Resolved') resolved
        WHERE pt.PlotThreadID = @PlotThreadID;
    END;

    SELECT @ThreadEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.ThreadEvent_Delete
    @ThreadEventID int
AS
BEGIN
    SET NOCOUNT ON;
    DELETE FROM dbo.ThreadEvents WHERE ThreadEventID = @ThreadEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneOption_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT s.SceneID, b.BookTitle, c.ChapterNumber, c.ChapterTitle, s.SceneNumber, s.SceneTitle
    FROM dbo.Scenes s
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND c.IsArchived = 0 AND s.IsArchived = 0
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Timeline_GetByProject
    @ProjectID int,
    @BookID int = NULL
AS
BEGIN
    SET NOCOUNT ON;

    SELECT ProjectID, ProjectName, Description, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Projects
    WHERE ProjectID = @ProjectID AND IsArchived = 0;

    SELECT BookID, ProjectID, BookTitle, BookNumber, Description, SortOrder, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Books
    WHERE ProjectID = @ProjectID AND IsArchived = 0 AND (@BookID IS NULL OR BookID = @BookID)
    ORDER BY SortOrder, BookNumber;

    SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, c.Summary,
        c.SortOrder, c.RevisionStatusID, rs.StatusName AS RevisionStatusName,
        c.CreatedDate, c.UpdatedDate, c.IsArchived
    FROM dbo.Chapters c
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID
    WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND c.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, c.ChapterNumber;

    SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.POVCharacterID,
        s.PrimaryLocationID, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime,
        s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText,
        s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes,
        s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived
    FROM dbo.Scenes s
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID
    LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID
    INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID
    INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID
    WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND c.IsArchived = 0 AND s.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, s.SceneNumber;

    SELECT sp.SceneID, spt.ScenePurposeTypeID, spt.PurposeName, spt.SortOrder
    FROM dbo.ScenePurposes sp
    INNER JOIN dbo.ScenePurposeTypes spt ON spt.ScenePurposeTypeID = sp.ScenePurposeTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = sp.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND c.IsArchived = 0 AND s.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY sp.SceneID, spt.SortOrder;

    SELECT MetricTypeID, ProjectID, MetricName, Description, MinValue, MaxValue, DefaultValue, SortOrder, IsActive
    FROM dbo.SceneMetricTypes
    WHERE IsActive = 1 AND (ProjectID IS NULL OR ProjectID = @ProjectID)
    ORDER BY SortOrder, MetricName;

    SELECT s.SceneID, mt.MetricTypeID, mt.MetricName, COALESCE(smv.Value, mt.DefaultValue) AS Value, smv.Notes
    FROM dbo.Scenes s
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    CROSS JOIN dbo.SceneMetricTypes mt
    LEFT JOIN dbo.SceneMetricValues smv ON smv.SceneID = s.SceneID AND smv.MetricTypeID = mt.MetricTypeID
    WHERE b.ProjectID = @ProjectID
        AND b.IsArchived = 0
        AND c.IsArchived = 0
        AND s.IsArchived = 0
        AND mt.IsActive = 1
        AND (mt.ProjectID IS NULL OR mt.ProjectID = @ProjectID)
        AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, mt.SortOrder;

    SELECT pl.PlotLineID, pl.ProjectID, pl.BookID, b.BookTitle, pl.PlotLineName, pl.PlotLineTypeID,
        plt.TypeName AS PlotLineTypeName, pl.Description, pl.ParentPlotLineID, parent.PlotLineName AS ParentPlotLineName,
        pl.SortOrder, pl.Colour, pl.IsMainPlot, pl.IsVisibleOnTimeline, pl.CreatedDate, pl.UpdatedDate, pl.IsArchived
    FROM dbo.PlotLines pl
    INNER JOIN dbo.PlotLineTypes plt ON plt.PlotLineTypeID = pl.PlotLineTypeID
    LEFT JOIN dbo.Books b ON b.BookID = pl.BookID
    LEFT JOIN dbo.PlotLines parent ON parent.PlotLineID = pl.ParentPlotLineID
    WHERE pl.ProjectID = @ProjectID
        AND pl.IsArchived = 0
        AND pl.IsVisibleOnTimeline = 1
        AND (@BookID IS NULL OR pl.BookID IS NULL OR pl.BookID = @BookID)
    ORDER BY pl.SortOrder, pl.PlotLineName;

    SELECT te.ThreadEventID, te.PlotThreadID, pt.ThreadTitle, pt.PlotLineID, pl.PlotLineName, pl.Colour,
        te.SceneID, te.EventTypeID, tet.TypeName AS EventTypeName, tet.MarkerText, te.EventTitle,
        te.EventDescription, te.CreatedDate, te.UpdatedDate
    FROM dbo.ThreadEvents te
    INNER JOIN dbo.PlotThreads pt ON pt.PlotThreadID = te.PlotThreadID
    INNER JOIN dbo.PlotLines pl ON pl.PlotLineID = pt.PlotLineID
    INNER JOIN dbo.ThreadEventTypes tet ON tet.ThreadEventTypeID = te.EventTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = te.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    WHERE b.ProjectID = @ProjectID
        AND b.IsArchived = 0
        AND c.IsArchived = 0
        AND s.IsArchived = 0
        AND pl.IsArchived = 0
        AND pl.IsVisibleOnTimeline = 1
        AND pt.IsArchived = 0
        AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY pl.SortOrder, b.SortOrder, c.SortOrder, s.SortOrder, te.CreatedDate;
END;
GO
