SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF COL_LENGTH(N'dbo.Characters', N'ShowInQuickAddBar') IS NULL
BEGIN
    ALTER TABLE dbo.Characters
        ADD ShowInQuickAddBar bit NOT NULL
            CONSTRAINT DF_Characters_ShowInQuickAddBar DEFAULT 0 WITH VALUES;
END;
GO

IF COL_LENGTH(N'dbo.StoryAssets', N'ShowInQuickAddBar') IS NULL
BEGIN
    ALTER TABLE dbo.StoryAssets
        ADD ShowInQuickAddBar bit NOT NULL
            CONSTRAINT DF_StoryAssets_ShowInQuickAddBar DEFAULT 0 WITH VALUES;
END;
GO

IF COL_LENGTH(N'dbo.Locations', N'ShowInQuickAddBar') IS NULL
BEGIN
    ALTER TABLE dbo.Locations
        ADD ShowInQuickAddBar bit NOT NULL
            CONSTRAINT DF_Locations_ShowInQuickAddBar DEFAULT 0 WITH VALUES;
END;
GO

UPDATE dbo.Characters
SET ShowInQuickAddBar = 1
WHERE ShowInQuickAddBar = 0 AND ISNULL(CharacterImportance, 0) >= 6;
GO

UPDATE dbo.StoryAssets
SET ShowInQuickAddBar = 1
WHERE ShowInQuickAddBar = 0 AND (Importance >= 5 OR IsResolved = 0);
GO

WITH RankedCharacters AS
(
    SELECT CharacterID,
        ROW_NUMBER() OVER (PARTITION BY ProjectID ORDER BY ISNULL(CharacterImportance, 0) DESC, CharacterName) AS RowNumber,
        SUM(CASE WHEN ShowInQuickAddBar = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY ProjectID) AS FlaggedCount
    FROM dbo.Characters
    WHERE IsArchived = 0
)
UPDATE c
SET ShowInQuickAddBar = 1
FROM dbo.Characters c
INNER JOIN RankedCharacters rc ON rc.CharacterID = c.CharacterID
WHERE rc.FlaggedCount = 0 AND rc.RowNumber <= 10;
GO

WITH RankedAssets AS
(
    SELECT StoryAssetID,
        ROW_NUMBER() OVER (PARTITION BY ProjectID ORDER BY Importance DESC, AssetName) AS RowNumber,
        SUM(CASE WHEN ShowInQuickAddBar = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY ProjectID) AS FlaggedCount
    FROM dbo.StoryAssets
    WHERE IsArchived = 0
)
UPDATE sa
SET ShowInQuickAddBar = 1
FROM dbo.StoryAssets sa
INNER JOIN RankedAssets ra ON ra.StoryAssetID = sa.StoryAssetID
WHERE ra.FlaggedCount = 0 AND ra.RowNumber <= 10;
GO

WITH RankedLocations AS
(
    SELECT lp.LocationID,
        ROW_NUMBER() OVER (PARTITION BY lp.ProjectID ORDER BY lp.SortPath) AS RowNumber,
        SUM(CASE WHEN l.ShowInQuickAddBar = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY lp.ProjectID) AS FlaggedCount
    FROM dbo.LocationPaths lp
    INNER JOIN dbo.Locations l ON l.LocationID = lp.LocationID
)
UPDATE l
SET ShowInQuickAddBar = 1
FROM dbo.Locations l
INNER JOIN RankedLocations rl ON rl.LocationID = l.LocationID
WHERE rl.FlaggedCount = 0 AND rl.RowNumber <= 10;
GO

CREATE OR ALTER PROCEDURE dbo.Character_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Characters
    WHERE ProjectID = @ProjectID AND IsArchived = 0
    ORDER BY CharacterName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Character_Get
    @CharacterID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Characters
    WHERE CharacterID = @CharacterID AND IsArchived = 0;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Character_Save
    @CharacterID int = NULL,
    @ProjectID int,
    @CharacterName nvarchar(200),
    @ShortName nvarchar(100) = NULL,
    @Sex nvarchar(50) = NULL,
    @BirthDate date = NULL,
    @AgeAtSeriesStart int = NULL,
    @AgeReferenceSceneID int = NULL,
    @Height nvarchar(50) = NULL,
    @EyeColour nvarchar(50) = NULL,
    @CharacterImportance int = NULL,
    @ShowInQuickAddBar bit = 0,
    @DefaultDescription nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @CharacterID IS NULL OR @CharacterID = 0
    BEGIN
        INSERT dbo.Characters (ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription)
        VALUES (@ProjectID, @CharacterName, @ShortName, @Sex, @BirthDate, @AgeAtSeriesStart, @AgeReferenceSceneID, @Height, @EyeColour, @CharacterImportance, @ShowInQuickAddBar, @DefaultDescription);
        SET @CharacterID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.Characters
        SET CharacterName = @CharacterName, ShortName = @ShortName, Sex = @Sex, BirthDate = @BirthDate,
            AgeAtSeriesStart = @AgeAtSeriesStart, AgeReferenceSceneID = @AgeReferenceSceneID,
            Height = @Height, EyeColour = @EyeColour, CharacterImportance = @CharacterImportance,
            ShowInQuickAddBar = @ShowInQuickAddBar, DefaultDescription = @DefaultDescription,
            UpdatedDate = SYSUTCDATETIME()
        WHERE CharacterID = @CharacterID;
    END
    SELECT @CharacterID;
END;
GO

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

    CREATE TABLE #TimelineScenes
    (
        SceneID int NOT NULL PRIMARY KEY,
        SceneNumber decimal(9,2) NOT NULL,
        SceneTitle nvarchar(200) NOT NULL,
        ChapterNumber decimal(9,2) NOT NULL,
        BookTitle nvarchar(200) NOT NULL,
        BookSortOrder int NOT NULL,
        ChapterSortOrder int NOT NULL,
        SceneSortOrder int NOT NULL
    );

    INSERT #TimelineScenes (SceneID, SceneNumber, SceneTitle, ChapterNumber, BookTitle, BookSortOrder, ChapterSortOrder, SceneSortOrder)
    SELECT s.SceneID, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle, b.SortOrder, ch.SortOrder, s.SortOrder
    FROM dbo.Books b
    INNER JOIN dbo.Chapters ch ON ch.BookID = b.BookID
    INNER JOIN dbo.Scenes s ON s.ChapterID = ch.ChapterID
    WHERE b.ProjectID = @ProjectID
        AND b.IsArchived = 0
        AND ch.IsArchived = 0
        AND s.IsArchived = 0
        AND (@BookID IS NULL OR b.BookID = @BookID);

    CREATE TABLE #TimelineCharacters
    (
        CharacterID int NOT NULL PRIMARY KEY,
        ProjectID int NOT NULL,
        CharacterName nvarchar(200) NOT NULL,
        ShortName nvarchar(100) NULL,
        Sex nvarchar(50) NULL,
        BirthDate date NULL,
        AgeAtSeriesStart int NULL,
        AgeReferenceSceneID int NULL,
        Height nvarchar(50) NULL,
        EyeColour nvarchar(50) NULL,
        CharacterImportance int NULL,
        ShowInQuickAddBar bit NOT NULL,
        DefaultDescription nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL,
        UpdatedDate datetime2 NOT NULL,
        IsArchived bit NOT NULL
    );

    INSERT #TimelineCharacters (CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived)
    SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
    FROM dbo.Characters
    WHERE ProjectID = @ProjectID AND IsArchived = 0;

    CREATE TABLE #ProjectLocationPaths
    (
        LocationID int NOT NULL PRIMARY KEY,
        LocationName nvarchar(200) NOT NULL,
        LocationPath nvarchar(max) NOT NULL
    );

    ;WITH ProjectLocationTree AS
    (
        SELECT LocationID, LocationName, CAST(LocationName AS nvarchar(max)) AS LocationPath
        FROM dbo.Locations
        WHERE ProjectID = @ProjectID AND ParentLocationID IS NULL AND IsArchived = 0

        UNION ALL

        SELECT child.LocationID, child.LocationName, CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)) AS LocationPath
        FROM dbo.Locations child
        INNER JOIN ProjectLocationTree parent ON parent.LocationID = child.ParentLocationID
        WHERE child.ProjectID = @ProjectID AND child.IsArchived = 0
    )
    INSERT #ProjectLocationPaths (LocationID, LocationName, LocationPath)
    SELECT LocationID, LocationName, LocationPath
    FROM ProjectLocationTree;

    SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
    FROM #TimelineCharacters
    ORDER BY ISNULL(CharacterImportance, 0) DESC, CharacterName;

    SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID, c.CharacterName, c.ShortName, c.BirthDate, c.AgeAtSeriesStart,
        sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName,
        sc.LocationID, location.LocationName, location.LocationPath, sc.EntryLocationID, entry.LocationName AS EntryLocationName,
        sc.ExitLocationID, exitLocation.LocationName AS ExitLocationName, sc.AppearanceNotes, sc.OutfitDescription,
        sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes, s.SceneNumber, s.SceneTitle, s.ChapterNumber, s.BookTitle,
        sc.CreatedDate, sc.UpdatedDate
    FROM #TimelineScenes s
    INNER JOIN dbo.SceneCharacters sc ON sc.SceneID = s.SceneID
    INNER JOIN #TimelineCharacters c ON c.CharacterID = sc.CharacterID
    LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
    LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
    LEFT JOIN #ProjectLocationPaths location ON location.LocationID = sc.LocationID
    LEFT JOIN #ProjectLocationPaths entry ON entry.LocationID = sc.EntryLocationID
    LEFT JOIN #ProjectLocationPaths exitLocation ON exitLocation.LocationID = sc.ExitLocationID
    ORDER BY s.BookSortOrder, s.ChapterSortOrder, s.SceneSortOrder, c.CharacterName;
END;
GO

CREATE OR ALTER VIEW dbo.LocationPaths
AS
WITH LocationTree AS
(
    SELECT LocationID, ProjectID, ParentLocationID, LocationName, LocationTypeID, Description, ShowInQuickAddBar,
        CAST(LocationName AS nvarchar(max)) AS LocationPath,
        CAST(RIGHT('000000' + CAST(LocationID AS varchar(6)), 6) AS nvarchar(max)) AS SortPath,
        0 AS Depth
    FROM dbo.Locations
    WHERE ParentLocationID IS NULL AND IsArchived = 0
    UNION ALL
    SELECT child.LocationID, child.ProjectID, child.ParentLocationID, child.LocationName, child.LocationTypeID, child.Description, child.ShowInQuickAddBar,
        CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)),
        CAST(parent.SortPath + N'.' + RIGHT('000000' + CAST(child.LocationID AS varchar(6)), 6) AS nvarchar(max)),
        parent.Depth + 1
    FROM dbo.Locations child
    INNER JOIN LocationTree parent ON parent.LocationID = child.ParentLocationID
    WHERE child.IsArchived = 0
)
SELECT LocationID, ProjectID, ParentLocationID, LocationName, LocationTypeID, Description, ShowInQuickAddBar, LocationPath, SortPath, Depth
FROM LocationTree;
GO

CREATE OR ALTER PROCEDURE dbo.Location_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lp.LocationID, lp.ProjectID, lp.ParentLocationID, lp.LocationName, lp.LocationTypeID, lt.TypeName AS LocationTypeName,
        lp.Description, lp.ShowInQuickAddBar, lp.LocationPath, lp.Depth, l.CreatedDate, l.UpdatedDate, l.IsArchived
    FROM dbo.LocationPaths lp
    INNER JOIN dbo.Locations l ON l.LocationID = lp.LocationID
    LEFT JOIN dbo.LocationTypes lt ON lt.LocationTypeID = lp.LocationTypeID
    WHERE lp.ProjectID = @ProjectID
    ORDER BY lp.SortPath;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_Get
    @LocationID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT lp.LocationID, lp.ProjectID, lp.ParentLocationID, parent.LocationName AS ParentLocationName,
        lp.LocationName, lp.LocationTypeID, lt.TypeName AS LocationTypeName, lp.Description, lp.ShowInQuickAddBar, lp.LocationPath, lp.Depth,
        l.CreatedDate, l.UpdatedDate, l.IsArchived
    FROM dbo.LocationPaths lp
    INNER JOIN dbo.Locations l ON l.LocationID = lp.LocationID
    LEFT JOIN dbo.Locations parent ON parent.LocationID = lp.ParentLocationID
    LEFT JOIN dbo.LocationTypes lt ON lt.LocationTypeID = lp.LocationTypeID
    WHERE lp.LocationID = @LocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Location_Save
    @LocationID int = NULL,
    @ProjectID int,
    @ParentLocationID int = NULL,
    @LocationName nvarchar(200),
    @LocationTypeID int = NULL,
    @Description nvarchar(max) = NULL,
    @ShowInQuickAddBar bit = 0
AS
BEGIN
    SET NOCOUNT ON;
    IF @LocationID IS NULL OR @LocationID = 0
    BEGIN
        INSERT dbo.Locations (ProjectID, ParentLocationID, LocationName, LocationTypeID, Description, ShowInQuickAddBar)
        VALUES (@ProjectID, @ParentLocationID, @LocationName, @LocationTypeID, @Description, @ShowInQuickAddBar);
        SET @LocationID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.Locations
        SET ParentLocationID = @ParentLocationID, LocationName = @LocationName, LocationTypeID = @LocationTypeID,
            Description = @Description, ShowInQuickAddBar = @ShowInQuickAddBar, UpdatedDate = SYSUTCDATETIME()
        WHERE LocationID = @LocationID;
    END
    SELECT @LocationID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_Save
    @StoryAssetID int = NULL, @ProjectID int, @AssetName nvarchar(200), @AssetKindID int, @Description nvarchar(max) = NULL,
    @Importance int, @CurrentStateID int = NULL, @CurrentLocationID int = NULL, @IsResolved bit, @ShowInQuickAddBar bit = 0
AS
BEGIN
    SET NOCOUNT ON;
    IF @StoryAssetID IS NULL OR @StoryAssetID = 0
    BEGIN
        INSERT dbo.StoryAssets (ProjectID, AssetName, AssetKindID, Description, Importance, CurrentStateID, CurrentLocationID, IsResolved, ShowInQuickAddBar)
        VALUES (@ProjectID, @AssetName, @AssetKindID, @Description, @Importance, @CurrentStateID, @CurrentLocationID, @IsResolved, @ShowInQuickAddBar);
        SET @StoryAssetID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.StoryAssets
        SET AssetName = @AssetName, AssetKindID = @AssetKindID, Description = @Description, Importance = @Importance,
            CurrentStateID = @CurrentStateID, CurrentLocationID = @CurrentLocationID, IsResolved = @IsResolved,
            ShowInQuickAddBar = @ShowInQuickAddBar, UpdatedDate = SYSUTCDATETIME()
        WHERE StoryAssetID = @StoryAssetID;
    END
    SELECT @StoryAssetID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.ShowInQuickAddBar, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0
    ORDER BY sa.Importance DESC, sa.AssetName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StoryAsset_Get
    @StoryAssetID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.ShowInQuickAddBar, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.StoryAssetID = @StoryAssetID AND sa.IsArchived = 0;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetTimeline_GetByProject
    @ProjectID int,
    @BookID int = NULL
AS
BEGIN
    SET NOCOUNT ON;
    SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance,
        sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID,
        location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath,
        sa.IsResolved, sa.ShowInQuickAddBar, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived
    FROM dbo.StoryAssets sa
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID
    LEFT JOIN dbo.LocationPaths location ON location.LocationID = sa.CurrentLocationID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 AND (sa.Importance >= 5 OR sa.IsResolved = 0)
    ORDER BY sa.Importance DESC, sa.AssetName;

    SELECT ae.AssetEventID, ae.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName,
        ae.SceneID, ae.AssetEventTypeID, aet.TypeName AS AssetEventTypeName, aet.MarkerText,
        ae.FromStateID, fs.StateName AS FromStateName, ae.ToStateID, ts.StateName AS ToStateName,
        ae.EventTitle, ae.EventDescription, ae.CreatedDate, ae.UpdatedDate
    FROM dbo.AssetEvents ae
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID
    INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID
    INNER JOIN dbo.AssetEventTypes aet ON aet.AssetEventTypeID = ae.AssetEventTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = ae.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    LEFT JOIN dbo.AssetStates fs ON fs.AssetStateID = ae.FromStateID
    LEFT JOIN dbo.AssetStates ts ON ts.AssetStateID = ae.ToStateID
    WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, sa.AssetName;
END;
GO
