SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF OBJECT_ID(N'dbo.AssetKinds', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetKinds
    (
        AssetKindID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetKinds PRIMARY KEY,
        KindName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_AssetKinds_IsActive DEFAULT 1,
        CONSTRAINT UQ_AssetKinds_KindName UNIQUE (KindName)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetStates', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetStates
    (
        AssetStateID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetStates PRIMARY KEY,
        ProjectID int NULL,
        AssetKindID int NULL,
        StateName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        Description nvarchar(max) NULL,
        IsResolvedState bit NOT NULL CONSTRAINT DF_AssetStates_IsResolvedState DEFAULT 0,
        IsActive bit NOT NULL CONSTRAINT DF_AssetStates_IsActive DEFAULT 1,
        CONSTRAINT FK_AssetStates_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_AssetStates_AssetKinds FOREIGN KEY (AssetKindID) REFERENCES dbo.AssetKinds(AssetKindID)
    );
END;
GO

IF OBJECT_ID(N'dbo.StoryAssets', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.StoryAssets
    (
        StoryAssetID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_StoryAssets PRIMARY KEY,
        ProjectID int NOT NULL,
        AssetName nvarchar(200) NOT NULL,
        AssetKindID int NOT NULL,
        Description nvarchar(max) NULL,
        Importance int NOT NULL CONSTRAINT DF_StoryAssets_Importance DEFAULT 5,
        CurrentStateID int NULL,
        CurrentLocationID int NULL,
        IsResolved bit NOT NULL CONSTRAINT DF_StoryAssets_IsResolved DEFAULT 0,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_StoryAssets_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_StoryAssets_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_StoryAssets_IsArchived DEFAULT 0,
        CONSTRAINT FK_StoryAssets_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
        CONSTRAINT FK_StoryAssets_AssetKinds FOREIGN KEY (AssetKindID) REFERENCES dbo.AssetKinds(AssetKindID),
        CONSTRAINT FK_StoryAssets_CurrentState FOREIGN KEY (CurrentStateID) REFERENCES dbo.AssetStates(AssetStateID),
        CONSTRAINT CK_StoryAssets_Importance CHECK (Importance BETWEEN 1 AND 10)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetEventTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetEventTypes
    (
        AssetEventTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetEventTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        MarkerText nvarchar(10) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_AssetEventTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_AssetEventTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetEvents', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetEvents
    (
        AssetEventID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetEvents PRIMARY KEY,
        StoryAssetID int NOT NULL,
        SceneID int NOT NULL,
        AssetEventTypeID int NOT NULL,
        FromStateID int NULL,
        ToStateID int NULL,
        EventTitle nvarchar(200) NOT NULL,
        EventDescription nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_AssetEvents_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_AssetEvents_UpdatedDate DEFAULT SYSUTCDATETIME(),
        CONSTRAINT FK_AssetEvents_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
        CONSTRAINT FK_AssetEvents_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_AssetEvents_AssetEventTypes FOREIGN KEY (AssetEventTypeID) REFERENCES dbo.AssetEventTypes(AssetEventTypeID),
        CONSTRAINT FK_AssetEvents_FromState FOREIGN KEY (FromStateID) REFERENCES dbo.AssetStates(AssetStateID),
        CONSTRAINT FK_AssetEvents_ToState FOREIGN KEY (ToStateID) REFERENCES dbo.AssetStates(AssetStateID)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetDependencyTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetDependencyTypes
    (
        AssetDependencyTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetDependencyTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsValidatingDependency bit NOT NULL CONSTRAINT DF_AssetDependencyTypes_IsValidatingDependency DEFAULT 0,
        IsActive bit NOT NULL CONSTRAINT DF_AssetDependencyTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_AssetDependencyTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetDependencies', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetDependencies
    (
        AssetDependencyID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetDependencies PRIMARY KEY,
        SourceAssetID int NOT NULL,
        TargetAssetID int NOT NULL,
        AssetDependencyTypeID int NOT NULL,
        SourceRequiredStateID int NULL,
        TargetBlockedStateID int NULL,
        Description nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_AssetDependencies_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_AssetDependencies_UpdatedDate DEFAULT SYSUTCDATETIME(),
        IsArchived bit NOT NULL CONSTRAINT DF_AssetDependencies_IsArchived DEFAULT 0,
        CONSTRAINT FK_AssetDependencies_SourceAsset FOREIGN KEY (SourceAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
        CONSTRAINT FK_AssetDependencies_TargetAsset FOREIGN KEY (TargetAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
        CONSTRAINT FK_AssetDependencies_Type FOREIGN KEY (AssetDependencyTypeID) REFERENCES dbo.AssetDependencyTypes(AssetDependencyTypeID),
        CONSTRAINT FK_AssetDependencies_SourceState FOREIGN KEY (SourceRequiredStateID) REFERENCES dbo.AssetStates(AssetStateID),
        CONSTRAINT FK_AssetDependencies_TargetState FOREIGN KEY (TargetBlockedStateID) REFERENCES dbo.AssetStates(AssetStateID)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetCustodyEventTypes', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetCustodyEventTypes
    (
        AssetCustodyEventTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetCustodyEventTypes PRIMARY KEY,
        TypeName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_AssetCustodyEventTypes_IsActive DEFAULT 1,
        CONSTRAINT UQ_AssetCustodyEventTypes_TypeName UNIQUE (TypeName)
    );
END;
GO

IF OBJECT_ID(N'dbo.CustodyRoles', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.CustodyRoles
    (
        CustodyRoleID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CustodyRoles PRIMARY KEY,
        RoleName nvarchar(100) NOT NULL,
        SortOrder int NOT NULL,
        IsActive bit NOT NULL CONSTRAINT DF_CustodyRoles_IsActive DEFAULT 1,
        CONSTRAINT UQ_CustodyRoles_RoleName UNIQUE (RoleName)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetCustodyEvents', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetCustodyEvents
    (
        AssetCustodyEventID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetCustodyEvents PRIMARY KEY,
        StoryAssetID int NOT NULL,
        SceneID int NOT NULL,
        AssetCustodyEventTypeID int NOT NULL,
        Description nvarchar(max) NULL,
        CreatedDate datetime2 NOT NULL CONSTRAINT DF_AssetCustodyEvents_CreatedDate DEFAULT SYSUTCDATETIME(),
        UpdatedDate datetime2 NOT NULL CONSTRAINT DF_AssetCustodyEvents_UpdatedDate DEFAULT SYSUTCDATETIME(),
        CONSTRAINT FK_AssetCustodyEvents_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
        CONSTRAINT FK_AssetCustodyEvents_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
        CONSTRAINT FK_AssetCustodyEvents_Type FOREIGN KEY (AssetCustodyEventTypeID) REFERENCES dbo.AssetCustodyEventTypes(AssetCustodyEventTypeID)
    );
END;
GO

IF OBJECT_ID(N'dbo.AssetCustodyEventCharacters', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.AssetCustodyEventCharacters
    (
        AssetCustodyEventCharacterID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_AssetCustodyEventCharacters PRIMARY KEY,
        AssetCustodyEventID int NOT NULL,
        CharacterID int NULL,
        CharacterNameText nvarchar(200) NULL,
        CustodyRoleID int NOT NULL,
        CONSTRAINT FK_AssetCustodyEventCharacters_Events FOREIGN KEY (AssetCustodyEventID) REFERENCES dbo.AssetCustodyEvents(AssetCustodyEventID) ON DELETE CASCADE,
        CONSTRAINT FK_AssetCustodyEventCharacters_Roles FOREIGN KEY (CustodyRoleID) REFERENCES dbo.CustodyRoles(CustodyRoleID)
    );
END;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryAssets_ProjectID' AND object_id = OBJECT_ID(N'dbo.StoryAssets'))
    CREATE INDEX IX_StoryAssets_ProjectID ON dbo.StoryAssets(ProjectID, IsArchived, Importance);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetEvents_SceneID' AND object_id = OBJECT_ID(N'dbo.AssetEvents'))
    CREATE INDEX IX_AssetEvents_SceneID ON dbo.AssetEvents(SceneID, StoryAssetID, AssetEventTypeID);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetDependencies_TargetAssetID' AND object_id = OBJECT_ID(N'dbo.AssetDependencies'))
    CREATE INDEX IX_AssetDependencies_TargetAssetID ON dbo.AssetDependencies(TargetAssetID, IsArchived, AssetDependencyTypeID);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetCustodyEvents_SceneID' AND object_id = OBJECT_ID(N'dbo.AssetCustodyEvents'))
    CREATE INDEX IX_AssetCustodyEvents_SceneID ON dbo.AssetCustodyEvents(SceneID, StoryAssetID);
GO

MERGE dbo.AssetKinds AS target
USING (VALUES
    (N'Physical Object', 10), (N'Clothing', 20), (N'Document', 30), (N'Evidence', 40),
    (N'Clue', 50), (N'Secret', 60), (N'Fact', 70), (N'Emotional Fact', 80),
    (N'Relationship Truth', 90), (N'Plan', 100), (N'Threat', 110), (N'Promise', 120),
    (N'Location Item', 130), (N'Vehicle', 140), (N'Money Trail', 150), (N'Other', 160)
) AS source (KindName, SortOrder)
ON target.KindName = source.KindName
WHEN NOT MATCHED THEN INSERT (KindName, SortOrder) VALUES (source.KindName, source.SortOrder);
GO

MERGE dbo.AssetStates AS target
USING (VALUES
    (N'Unknown', 10, 0), (N'Mentioned', 20, 0), (N'Known To Exist', 30, 0), (N'Found', 40, 0),
    (N'Possessed', 50, 0), (N'Investigated', 60, 0), (N'Identified', 70, 0), (N'Used', 80, 0),
    (N'Lost', 90, 0), (N'Hidden', 100, 0), (N'Revealed', 110, 0), (N'Opened', 120, 0),
    (N'Destroyed', 130, 1), (N'Resolved', 140, 1)
) AS source (StateName, SortOrder, IsResolvedState)
ON target.ProjectID IS NULL AND target.AssetKindID IS NULL AND target.StateName = source.StateName
WHEN NOT MATCHED THEN INSERT (StateName, SortOrder, IsResolvedState) VALUES (source.StateName, source.SortOrder, source.IsResolvedState);
GO

MERGE dbo.AssetEventTypes AS target
USING (VALUES
    (N'Mentioned', N'M', 10), (N'First Mentioned', N'I', 20), (N'Found', N'F', 30),
    (N'Lost', N'L', 40), (N'Given', N'G', 50), (N'Taken', N'T', 60), (N'Stolen', N'S', 70),
    (N'Hidden', N'H', 80), (N'Moved', N'Mv', 90), (N'Used', N'U', 100), (N'Opened', N'O', 110),
    (N'Destroyed', N'X', 120), (N'Revealed', N'R', 130), (N'Investigated', N'?', 140),
    (N'State Changed', N'C', 150), (N'Custody Changed', N'Cc', 160), (N'Location Changed', N'Loc', 170),
    (N'Note', N'N', 180)
) AS source (TypeName, MarkerText, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, MarkerText, SortOrder) VALUES (source.TypeName, source.MarkerText, source.SortOrder);
GO

MERGE dbo.AssetDependencyTypes AS target
USING (VALUES
    (N'Requires', 10, 1), (N'Unlocks', 20, 1), (N'Reveals', 30, 0), (N'Leads To', 40, 0),
    (N'Contains', 50, 0), (N'Contradicts', 60, 0), (N'Supports', 70, 0), (N'Related To', 80, 0)
) AS source (TypeName, SortOrder, IsValidatingDependency)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder, IsValidatingDependency) VALUES (source.TypeName, source.SortOrder, source.IsValidatingDependency);
GO

MERGE dbo.AssetCustodyEventTypes AS target
USING (VALUES
    (N'Has', 10), (N'Shared Custody', 20), (N'Given To', 30), (N'Taken From', 40),
    (N'Stolen By', 50), (N'Hidden By', 60), (N'Found By', 70), (N'Used By', 80),
    (N'Observed By', 90), (N'Left With', 100), (N'Lost By', 110), (N'Returned To', 120)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder) VALUES (source.TypeName, source.SortOrder);
GO

MERGE dbo.CustodyRoles AS target
USING (VALUES
    (N'Has Custody', 10), (N'Shared Custody', 20), (N'Handles', 30), (N'Uses', 40),
    (N'Observes', 50), (N'Transfers From', 60), (N'Transfers To', 70), (N'Steals From', 80),
    (N'Hides', 90), (N'Finds', 100)
) AS source (RoleName, SortOrder)
ON target.RoleName = source.RoleName
WHEN NOT MATCHED THEN INSERT (RoleName, SortOrder) VALUES (source.RoleName, source.SortOrder);
GO

CREATE OR ALTER PROCEDURE dbo.AssetLookup_All
AS
BEGIN
    SET NOCOUNT ON;
    SELECT AssetKindID, KindName, SortOrder, IsActive FROM dbo.AssetKinds WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT AssetStateID, ProjectID, AssetKindID, StateName, SortOrder, Description, IsResolvedState, IsActive FROM dbo.AssetStates WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT AssetEventTypeID, TypeName, MarkerText, SortOrder, IsActive FROM dbo.AssetEventTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT AssetDependencyTypeID, TypeName, SortOrder, IsValidatingDependency, IsActive FROM dbo.AssetDependencyTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT AssetCustodyEventTypeID, TypeName, SortOrder, IsActive FROM dbo.AssetCustodyEventTypes WHERE IsActive = 1 ORDER BY SortOrder;
    SELECT CustodyRoleID, RoleName, SortOrder, IsActive FROM dbo.CustodyRoles WHERE IsActive = 1 ORDER BY SortOrder;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetKind_List AS BEGIN SET NOCOUNT ON; SELECT AssetKindID, KindName, SortOrder, IsActive FROM dbo.AssetKinds WHERE IsActive = 1 ORDER BY SortOrder; END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetState_List AS BEGIN SET NOCOUNT ON; SELECT AssetStateID, ProjectID, AssetKindID, StateName, SortOrder, Description, IsResolvedState, IsActive FROM dbo.AssetStates WHERE IsActive = 1 ORDER BY SortOrder; END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetEventType_List AS BEGIN SET NOCOUNT ON; SELECT AssetEventTypeID, TypeName, MarkerText, SortOrder, IsActive FROM dbo.AssetEventTypes WHERE IsActive = 1 ORDER BY SortOrder; END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetDependencyType_List AS BEGIN SET NOCOUNT ON; SELECT AssetDependencyTypeID, TypeName, SortOrder, IsValidatingDependency, IsActive FROM dbo.AssetDependencyTypes WHERE IsActive = 1 ORDER BY SortOrder; END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetCustodyEventType_List AS BEGIN SET NOCOUNT ON; SELECT AssetCustodyEventTypeID, TypeName, SortOrder, IsActive FROM dbo.AssetCustodyEventTypes WHERE IsActive = 1 ORDER BY SortOrder; END;
GO
CREATE OR ALTER PROCEDURE dbo.CustodyRole_List AS BEGIN SET NOCOUNT ON; SELECT CustodyRoleID, RoleName, SortOrder, IsActive FROM dbo.CustodyRoles WHERE IsActive = 1 ORDER BY SortOrder; 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, sa.IsResolved,
        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
    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, sa.IsResolved,
        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
    WHERE sa.StoryAssetID = @StoryAssetID AND sa.IsArchived = 0;
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,
    @IsResolved bit
AS
BEGIN
    SET NOCOUNT ON;

    IF @StoryAssetID IS NULL OR @StoryAssetID = 0
    BEGIN
        INSERT dbo.StoryAssets (ProjectID, AssetName, AssetKindID, Description, Importance, CurrentStateID, IsResolved)
        VALUES (@ProjectID, @AssetName, @AssetKindID, @Description, @Importance, @CurrentStateID, @IsResolved);
        SET @StoryAssetID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.StoryAssets
        SET AssetName = @AssetName,
            AssetKindID = @AssetKindID,
            Description = @Description,
            Importance = @Importance,
            CurrentStateID = @CurrentStateID,
            IsResolved = @IsResolved,
            UpdatedDate = SYSUTCDATETIME()
        WHERE StoryAssetID = @StoryAssetID;
    END

    SELECT @StoryAssetID;
END;
GO

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

CREATE OR ALTER PROCEDURE dbo.AssetEvent_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    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
    LEFT JOIN dbo.AssetStates fs ON fs.AssetStateID = ae.FromStateID
    LEFT JOIN dbo.AssetStates ts ON ts.AssetStateID = ae.ToStateID
    WHERE ae.SceneID = @SceneID
    ORDER BY sa.AssetName, ae.AssetEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetEvent_ListByAsset
    @StoryAssetID int
AS
BEGIN
    SET NOCOUNT ON;
    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,
        b.BookTitle, c.ChapterNumber, s.SceneNumber, s.SceneTitle
    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 ae.StoryAssetID = @StoryAssetID
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, ae.AssetEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetEvent_Save
    @AssetEventID int = NULL,
    @StoryAssetID int,
    @SceneID int,
    @AssetEventTypeID int,
    @FromStateID int = NULL,
    @ToStateID int = NULL,
    @EventTitle nvarchar(200),
    @EventDescription nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    IF @AssetEventID IS NULL OR @AssetEventID = 0
    BEGIN
        INSERT dbo.AssetEvents (StoryAssetID, SceneID, AssetEventTypeID, FromStateID, ToStateID, EventTitle, EventDescription)
        VALUES (@StoryAssetID, @SceneID, @AssetEventTypeID, @FromStateID, @ToStateID, @EventTitle, @EventDescription);
        SET @AssetEventID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.AssetEvents
        SET StoryAssetID = @StoryAssetID,
            SceneID = @SceneID,
            AssetEventTypeID = @AssetEventTypeID,
            FromStateID = @FromStateID,
            ToStateID = @ToStateID,
            EventTitle = @EventTitle,
            EventDescription = @EventDescription,
            UpdatedDate = SYSUTCDATETIME()
        WHERE AssetEventID = @AssetEventID;
    END

    IF @ToStateID IS NOT NULL
    BEGIN
        UPDATE dbo.StoryAssets
        SET CurrentStateID = @ToStateID,
            IsResolved = CASE WHEN EXISTS (SELECT 1 FROM dbo.AssetStates WHERE AssetStateID = @ToStateID AND IsResolvedState = 1) THEN 1 ELSE IsResolved END,
            UpdatedDate = SYSUTCDATETIME()
        WHERE StoryAssetID = @StoryAssetID;
    END

    SELECT @AssetEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetEvent_Delete
    @AssetEventID int
AS
BEGIN
    SET NOCOUNT ON;
    DELETE FROM dbo.AssetEvents WHERE AssetEventID = @AssetEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetDependency_ListByAsset
    @StoryAssetID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT ad.AssetDependencyID, ad.SourceAssetID, source.AssetName AS SourceAssetName,
        ad.TargetAssetID, target.AssetName AS TargetAssetName,
        ad.AssetDependencyTypeID, adt.TypeName AS DependencyTypeName, adt.IsValidatingDependency,
        ad.SourceRequiredStateID, srs.StateName AS SourceRequiredStateName,
        ad.TargetBlockedStateID, tbs.StateName AS TargetBlockedStateName,
        ad.Description, ad.CreatedDate, ad.UpdatedDate, ad.IsArchived
    FROM dbo.AssetDependencies ad
    INNER JOIN dbo.StoryAssets source ON source.StoryAssetID = ad.SourceAssetID
    INNER JOIN dbo.StoryAssets target ON target.StoryAssetID = ad.TargetAssetID
    INNER JOIN dbo.AssetDependencyTypes adt ON adt.AssetDependencyTypeID = ad.AssetDependencyTypeID
    LEFT JOIN dbo.AssetStates srs ON srs.AssetStateID = ad.SourceRequiredStateID
    LEFT JOIN dbo.AssetStates tbs ON tbs.AssetStateID = ad.TargetBlockedStateID
    WHERE ad.IsArchived = 0 AND (@StoryAssetID IN (ad.SourceAssetID, ad.TargetAssetID))
    ORDER BY ad.AssetDependencyID DESC;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetDependency_Save
    @AssetDependencyID int = NULL,
    @SourceAssetID int,
    @TargetAssetID int,
    @AssetDependencyTypeID int,
    @SourceRequiredStateID int = NULL,
    @TargetBlockedStateID int = NULL,
    @Description nvarchar(max) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @AssetDependencyID IS NULL OR @AssetDependencyID = 0
    BEGIN
        INSERT dbo.AssetDependencies (SourceAssetID, TargetAssetID, AssetDependencyTypeID, SourceRequiredStateID, TargetBlockedStateID, Description)
        VALUES (@SourceAssetID, @TargetAssetID, @AssetDependencyTypeID, @SourceRequiredStateID, @TargetBlockedStateID, @Description);
        SET @AssetDependencyID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.AssetDependencies
        SET SourceAssetID = @SourceAssetID,
            TargetAssetID = @TargetAssetID,
            AssetDependencyTypeID = @AssetDependencyTypeID,
            SourceRequiredStateID = @SourceRequiredStateID,
            TargetBlockedStateID = @TargetBlockedStateID,
            Description = @Description,
            UpdatedDate = SYSUTCDATETIME()
        WHERE AssetDependencyID = @AssetDependencyID;
    END
    SELECT @AssetDependencyID;
END;
GO

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

CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID,
        ace.AssetCustodyEventTypeID, acet.TypeName AS CustodyEventTypeName, ace.Description,
        STRING_AGG(CONCAT(aec.CharacterNameText, N' (', cr.RoleName, N')'), N', ') AS CustodianSummary,
        ace.CreatedDate, ace.UpdatedDate
    FROM dbo.AssetCustodyEvents ace
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
    INNER JOIN dbo.AssetCustodyEventTypes acet ON acet.AssetCustodyEventTypeID = ace.AssetCustodyEventTypeID
    LEFT JOIN dbo.AssetCustodyEventCharacters aec ON aec.AssetCustodyEventID = ace.AssetCustodyEventID
    LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = aec.CustodyRoleID
    WHERE ace.SceneID = @SceneID
    GROUP BY ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID, ace.AssetCustodyEventTypeID, acet.TypeName, ace.Description, ace.CreatedDate, ace.UpdatedDate
    ORDER BY sa.AssetName, ace.AssetCustodyEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_ListByAsset
    @StoryAssetID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID,
        ace.AssetCustodyEventTypeID, acet.TypeName AS CustodyEventTypeName, ace.Description,
        STRING_AGG(CONCAT(aec.CharacterNameText, N' (', cr.RoleName, N')'), N', ') AS CustodianSummary,
        ace.CreatedDate, ace.UpdatedDate, b.BookTitle, c.ChapterNumber, s.SceneNumber, s.SceneTitle
    FROM dbo.AssetCustodyEvents ace
    INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
    INNER JOIN dbo.AssetCustodyEventTypes acet ON acet.AssetCustodyEventTypeID = ace.AssetCustodyEventTypeID
    INNER JOIN dbo.Scenes s ON s.SceneID = ace.SceneID
    INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
    INNER JOIN dbo.Books b ON b.BookID = c.BookID
    LEFT JOIN dbo.AssetCustodyEventCharacters aec ON aec.AssetCustodyEventID = ace.AssetCustodyEventID
    LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = aec.CustodyRoleID
    WHERE ace.StoryAssetID = @StoryAssetID
    GROUP BY ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID, ace.AssetCustodyEventTypeID, acet.TypeName, ace.Description, ace.CreatedDate, ace.UpdatedDate, b.BookTitle, c.ChapterNumber, s.SceneNumber, s.SceneTitle, b.SortOrder, c.SortOrder, s.SortOrder
    ORDER BY b.SortOrder, c.SortOrder, s.SortOrder, ace.AssetCustodyEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_Save
    @AssetCustodyEventID int = NULL,
    @StoryAssetID int,
    @SceneID int,
    @AssetCustodyEventTypeID int,
    @Description nvarchar(max) = NULL,
    @CustodianNames nvarchar(max) = NULL,
    @CustodyRoleID int
AS
BEGIN
    SET NOCOUNT ON;

    IF @AssetCustodyEventID IS NULL OR @AssetCustodyEventID = 0
    BEGIN
        INSERT dbo.AssetCustodyEvents (StoryAssetID, SceneID, AssetCustodyEventTypeID, Description)
        VALUES (@StoryAssetID, @SceneID, @AssetCustodyEventTypeID, @Description);
        SET @AssetCustodyEventID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.AssetCustodyEvents
        SET StoryAssetID = @StoryAssetID,
            SceneID = @SceneID,
            AssetCustodyEventTypeID = @AssetCustodyEventTypeID,
            Description = @Description,
            UpdatedDate = SYSUTCDATETIME()
        WHERE AssetCustodyEventID = @AssetCustodyEventID;
    END

    DELETE FROM dbo.AssetCustodyEventCharacters WHERE AssetCustodyEventID = @AssetCustodyEventID;

    INSERT dbo.AssetCustodyEventCharacters (AssetCustodyEventID, CharacterNameText, CustodyRoleID)
    SELECT @AssetCustodyEventID, LTRIM(RTRIM(value)), @CustodyRoleID
    FROM STRING_SPLIT(REPLACE(ISNULL(@CustodianNames, N''), CHAR(10), N','), N',')
    WHERE LTRIM(RTRIM(value)) <> N'';

    SELECT @AssetCustodyEventID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_Delete
    @AssetCustodyEventID int
AS
BEGIN
    SET NOCOUNT ON;
    DELETE FROM dbo.AssetCustodyEvents WHERE AssetCustodyEventID = @AssetCustodyEventID;
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, sa.IsResolved,
        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
    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

CREATE OR ALTER PROCEDURE dbo.AssetDependency_CheckForEvent
    @StoryAssetID int,
    @SceneID int,
    @ToStateID int = NULL
AS
BEGIN
    SET NOCOUNT ON;

    ;WITH CurrentScene AS
    (
        SELECT b.SortOrder AS BookSortOrder, c.SortOrder AS ChapterSortOrder, s.SortOrder AS SceneSortOrder
        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 s.SceneID = @SceneID
    )
    SELECT ad.AssetDependencyID, source.AssetName AS SourceAssetName, target.AssetName AS TargetAssetName,
        adt.TypeName AS DependencyTypeName, srs.StateName AS SourceRequiredStateName,
        tbs.StateName AS TargetBlockedStateName, ad.Description
    FROM dbo.AssetDependencies ad
    INNER JOIN dbo.AssetDependencyTypes adt ON adt.AssetDependencyTypeID = ad.AssetDependencyTypeID
    INNER JOIN dbo.StoryAssets source ON source.StoryAssetID = ad.SourceAssetID
    INNER JOIN dbo.StoryAssets target ON target.StoryAssetID = ad.TargetAssetID
    LEFT JOIN dbo.AssetStates srs ON srs.AssetStateID = ad.SourceRequiredStateID
    LEFT JOIN dbo.AssetStates tbs ON tbs.AssetStateID = ad.TargetBlockedStateID
    CROSS JOIN CurrentScene cs
    WHERE ad.IsArchived = 0
        AND adt.IsValidatingDependency = 1
        AND ad.TargetAssetID = @StoryAssetID
        AND (@ToStateID IS NULL OR ad.TargetBlockedStateID IS NULL OR ad.TargetBlockedStateID = @ToStateID)
        AND ad.SourceRequiredStateID IS NOT NULL
        AND NOT EXISTS
        (
            SELECT 1
            FROM dbo.AssetEvents ae
            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
            WHERE ae.StoryAssetID = ad.SourceAssetID
                AND ae.ToStateID = ad.SourceRequiredStateID
                AND (
                    b.SortOrder < cs.BookSortOrder
                    OR (b.SortOrder = cs.BookSortOrder AND c.SortOrder < cs.ChapterSortOrder)
                    OR (b.SortOrder = cs.BookSortOrder AND c.SortOrder = cs.ChapterSortOrder AND s.SortOrder < cs.SceneSortOrder)
                )
        );
END;
GO
