SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF OBJECT_ID(N'dbo.CharacterSexValues', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.CharacterSexValues
    (
        CharacterSexValueID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterSexValues PRIMARY KEY,
        OwnerUserID int NULL,
        SexName nvarchar(100) NOT NULL,
        IsSystem bit NOT NULL CONSTRAINT DF_CharacterSexValues_IsSystem DEFAULT (0),
        SortOrder int NOT NULL CONSTRAINT DF_CharacterSexValues_SortOrder DEFAULT (0),
        IsActive bit NOT NULL CONSTRAINT DF_CharacterSexValues_IsActive DEFAULT (1),
        CreatedDateUTC datetime2 NOT NULL CONSTRAINT DF_CharacterSexValues_CreatedDateUTC DEFAULT (SYSUTCDATETIME()),
        CONSTRAINT FK_CharacterSexValues_AppUser FOREIGN KEY (OwnerUserID) REFERENCES dbo.AppUser(UserID)
    );
END;
GO

IF COL_LENGTH(N'dbo.Characters', N'SexValueID') IS NULL
    ALTER TABLE dbo.Characters ADD SexValueID int NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = N'FK_Characters_CharacterSexValues')
    ALTER TABLE dbo.Characters ADD CONSTRAINT FK_Characters_CharacterSexValues FOREIGN KEY (SexValueID) REFERENCES dbo.CharacterSexValues(CharacterSexValueID);
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_CharacterSexValues_SystemName' AND object_id = OBJECT_ID(N'dbo.CharacterSexValues'))
    CREATE UNIQUE INDEX UX_CharacterSexValues_SystemName ON dbo.CharacterSexValues(SexName) WHERE IsSystem = 1 AND IsActive = 1;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_CharacterSexValues_OwnerName' AND object_id = OBJECT_ID(N'dbo.CharacterSexValues'))
    CREATE UNIQUE INDEX UX_CharacterSexValues_OwnerName ON dbo.CharacterSexValues(OwnerUserID, SexName) WHERE OwnerUserID IS NOT NULL AND IsActive = 1;
GO

IF NOT EXISTS (SELECT 1 FROM dbo.CharacterSexValues WHERE IsSystem = 1 AND SexName = N'Male')
    INSERT dbo.CharacterSexValues (OwnerUserID, SexName, IsSystem, SortOrder) VALUES (NULL, N'Male', 1, 10);
GO

IF NOT EXISTS (SELECT 1 FROM dbo.CharacterSexValues WHERE IsSystem = 1 AND SexName = N'Female')
    INSERT dbo.CharacterSexValues (OwnerUserID, SexName, IsSystem, SortOrder) VALUES (NULL, N'Female', 1, 20);
GO

IF NOT EXISTS (SELECT 1 FROM dbo.CharacterSexValues WHERE IsSystem = 1 AND SexName = N'Other')
    INSERT dbo.CharacterSexValues (OwnerUserID, SexName, IsSystem, SortOrder) VALUES (NULL, N'Other', 1, 30);
GO

;WITH CharacterOwners AS
(
    SELECT c.CharacterID, ownerAccess.UserID AS OwnerUserID, LTRIM(RTRIM(c.Sex)) AS SexName
    FROM dbo.Characters c
    INNER JOIN dbo.ProjectUserAccess ownerAccess ON ownerAccess.ProjectID = c.ProjectID
        AND ownerAccess.AccessRole = N'Owner'
        AND ownerAccess.IsActive = 1
    WHERE NULLIF(LTRIM(RTRIM(c.Sex)), N'') IS NOT NULL
),
CustomSexValues AS
(
    SELECT DISTINCT co.OwnerUserID, co.SexName
    FROM CharacterOwners co
    WHERE NOT EXISTS
    (
        SELECT 1
        FROM dbo.CharacterSexValues csv
        WHERE csv.IsSystem = 1
            AND csv.IsActive = 1
            AND LOWER(csv.SexName) = LOWER(co.SexName)
    )
      AND NOT EXISTS
    (
        SELECT 1
        FROM dbo.CharacterSexValues csv
        WHERE csv.OwnerUserID = co.OwnerUserID
            AND csv.IsActive = 1
            AND LOWER(csv.SexName) = LOWER(co.SexName)
    )
)
INSERT dbo.CharacterSexValues (OwnerUserID, SexName, IsSystem, SortOrder)
SELECT OwnerUserID, SexName, 0, 100
FROM CustomSexValues;
GO

;WITH CharacterOwners AS
(
    SELECT c.CharacterID, ownerAccess.UserID AS OwnerUserID, LTRIM(RTRIM(c.Sex)) AS SexName
    FROM dbo.Characters c
    INNER JOIN dbo.ProjectUserAccess ownerAccess ON ownerAccess.ProjectID = c.ProjectID
        AND ownerAccess.AccessRole = N'Owner'
        AND ownerAccess.IsActive = 1
    WHERE NULLIF(LTRIM(RTRIM(c.Sex)), N'') IS NOT NULL
)
UPDATE c
SET SexValueID = csv.CharacterSexValueID
FROM dbo.Characters c
INNER JOIN CharacterOwners co ON co.CharacterID = c.CharacterID
INNER JOIN dbo.CharacterSexValues csv ON csv.IsActive = 1
    AND LOWER(csv.SexName) = LOWER(co.SexName)
    AND (csv.IsSystem = 1 OR csv.OwnerUserID = co.OwnerUserID)
WHERE c.SexValueID IS NULL;
GO

CREATE OR ALTER PROCEDURE dbo.CharacterSexValue_GetOrCreate
    @OwnerUserID int,
    @SexName nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;

    SET @SexName = NULLIF(LTRIM(RTRIM(@SexName)), N'');
    IF @SexName IS NULL
        THROW 53001, 'Sex name is required.', 1;

    DECLARE @CharacterSexValueID int;

    SELECT TOP (1) @CharacterSexValueID = CharacterSexValueID
    FROM dbo.CharacterSexValues
    WHERE IsActive = 1
        AND LOWER(SexName) = LOWER(@SexName)
        AND (IsSystem = 1 OR OwnerUserID = @OwnerUserID)
    ORDER BY IsSystem DESC, SortOrder, SexName;

    IF @CharacterSexValueID IS NULL
    BEGIN
        INSERT dbo.CharacterSexValues (OwnerUserID, SexName, IsSystem, SortOrder)
        VALUES (@OwnerUserID, @SexName, 0, 100);

        SET @CharacterSexValueID = CAST(SCOPE_IDENTITY() AS int);
    END

    SELECT @CharacterSexValueID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.Character_ListByProject
    @ProjectID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT CharacterID, ProjectID, CharacterName, ShortName, SexValueID, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, ImagePath, ThumbnailPath,
        AvatarSourceCharacterImageID, AvatarImagePath, AvatarThumbnailPath,
        CreatedDate, UpdatedDate, IsArchived, ArchivedDate, ArchivedReason
    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, SexValueID, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
        Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, ImagePath, ThumbnailPath,
        AvatarSourceCharacterImageID, AvatarImagePath, AvatarThumbnailPath,
        CreatedDate, UpdatedDate, IsArchived, ArchivedDate, ArchivedReason
    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,
    @SexValueID int = NULL,
    @Sex nvarchar(100) = 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,
    @ImagePath nvarchar(500) = NULL,
    @ThumbnailPath nvarchar(500) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    IF @CharacterID IS NULL OR @CharacterID = 0
    BEGIN
        INSERT dbo.Characters (ProjectID, CharacterName, ShortName, SexValueID, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, ImagePath, ThumbnailPath)
        VALUES (@ProjectID, @CharacterName, @ShortName, @SexValueID, @Sex, @BirthDate, @AgeAtSeriesStart, @AgeReferenceSceneID, @Height, @EyeColour, @CharacterImportance, @ShowInQuickAddBar, @DefaultDescription, @ImagePath, @ThumbnailPath);
        SET @CharacterID = CAST(SCOPE_IDENTITY() AS int);
    END
    ELSE
    BEGIN
        UPDATE dbo.Characters
        SET CharacterName = @CharacterName, ShortName = @ShortName, SexValueID = @SexValueID, Sex = @Sex, BirthDate = @BirthDate,
            AgeAtSeriesStart = @AgeAtSeriesStart, AgeReferenceSceneID = @AgeReferenceSceneID,
            Height = @Height, EyeColour = @EyeColour, CharacterImportance = @CharacterImportance,
            ShowInQuickAddBar = @ShowInQuickAddBar, DefaultDescription = @DefaultDescription,
            ImagePath = @ImagePath, ThumbnailPath = @ThumbnailPath,
            UpdatedDate = SYSUTCDATETIME()
        WHERE CharacterID = @CharacterID;
    END
    SELECT @CharacterID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneFloorPlanOccupancy_ListByScene
    @SceneID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT o.SceneFloorPlanOccupancyID, o.SceneID, o.FloorPlanID, o.FloorPlanFloorID,
        o.CharacterID, c.CharacterName, c.ShortName AS CharacterShortName,
        COALESCE(c.AvatarImagePath, c.ImagePath) AS CharacterImagePath,
        COALESCE(c.AvatarThumbnailPath, c.ThumbnailPath) AS CharacterThumbnailPath,
        o.StoryAssetID, sa.AssetName, sa.ImagePath AS AssetImagePath, sa.ThumbnailPath AS AssetThumbnailPath,
        o.LocationID, COALESCE(lp.LocationName, l.LocationName) AS LocationName, COALESCE(lp.LocationPath, l.LocationName) AS LocationPath,
        fpf.Name AS FloorName, o.CreatedDate, o.ModifiedDate
    FROM dbo.SceneFloorPlanOccupancy o
    INNER JOIN dbo.Locations l ON l.LocationID = o.LocationID
    LEFT JOIN dbo.LocationPaths lp ON lp.LocationID = o.LocationID
    LEFT JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = o.FloorPlanFloorID
    LEFT JOIN dbo.Characters c ON c.CharacterID = o.CharacterID
    LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = o.StoryAssetID
    WHERE o.SceneID = @SceneID
    ORDER BY COALESCE(c.CharacterName, sa.AssetName);
END;
GO

CREATE OR ALTER PROCEDURE dbo.SceneFloorPlanOccupancy_ListByFloorPlan
    @FloorPlanID int
AS
BEGIN
    SET NOCOUNT ON;
    SELECT o.SceneFloorPlanOccupancyID, o.SceneID, o.FloorPlanID, o.FloorPlanFloorID,
        o.CharacterID, c.CharacterName, c.ShortName AS CharacterShortName,
        COALESCE(c.AvatarImagePath, c.ImagePath) AS CharacterImagePath,
        COALESCE(c.AvatarThumbnailPath, c.ThumbnailPath) AS CharacterThumbnailPath,
        o.StoryAssetID, sa.AssetName, sa.ImagePath AS AssetImagePath, sa.ThumbnailPath AS AssetThumbnailPath,
        o.LocationID, COALESCE(lp.LocationName, l.LocationName) AS LocationName, COALESCE(lp.LocationPath, l.LocationName) AS LocationPath,
        fpf.Name AS FloorName, o.CreatedDate, o.ModifiedDate
    FROM dbo.SceneFloorPlanOccupancy o
    INNER JOIN dbo.Locations l ON l.LocationID = o.LocationID
    LEFT JOIN dbo.LocationPaths lp ON lp.LocationID = o.LocationID
    LEFT JOIN dbo.FloorPlanFloors fpf ON fpf.FloorPlanFloorID = o.FloorPlanFloorID
    LEFT JOIN dbo.Characters c ON c.CharacterID = o.CharacterID
    LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = o.StoryAssetID
    WHERE o.FloorPlanID = @FloorPlanID
    ORDER BY o.SceneID, COALESCE(c.CharacterName, sa.AssetName);
END;
GO
