SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.SubscriptionLevel') AND name = N'StripeMonthlyPriceId')
    ALTER TABLE dbo.SubscriptionLevel ADD StripeMonthlyPriceId nvarchar(100) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.SubscriptionLevel') AND name = N'StripeAnnualPriceId')
    ALTER TABLE dbo.SubscriptionLevel ADD StripeAnnualPriceId nvarchar(100) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.SubscriptionLevel') AND name = N'RequiresStripeSubscription')
    ALTER TABLE dbo.SubscriptionLevel ADD RequiresStripeSubscription bit NOT NULL CONSTRAINT DF_SubscriptionLevel_RequiresStripeSubscription DEFAULT 0;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'StripeCustomerId')
    ALTER TABLE dbo.UserSubscription ADD StripeCustomerId nvarchar(100) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'StripeSubscriptionId')
    ALTER TABLE dbo.UserSubscription ADD StripeSubscriptionId nvarchar(100) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'StripePriceId')
    ALTER TABLE dbo.UserSubscription ADD StripePriceId nvarchar(100) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'BillingInterval')
    ALTER TABLE dbo.UserSubscription ADD BillingInterval nvarchar(20) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'StripeStatus')
    ALTER TABLE dbo.UserSubscription ADD StripeStatus nvarchar(50) NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'CurrentPeriodStartUTC')
    ALTER TABLE dbo.UserSubscription ADD CurrentPeriodStartUTC datetime2 NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'CurrentPeriodEndUTC')
    ALTER TABLE dbo.UserSubscription ADD CurrentPeriodEndUTC datetime2 NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'CancelAtPeriodEnd')
    ALTER TABLE dbo.UserSubscription ADD CancelAtPeriodEnd bit NOT NULL CONSTRAINT DF_UserSubscription_CancelAtPeriodEnd DEFAULT 0;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'CancelledDateUTC')
    ALTER TABLE dbo.UserSubscription ADD CancelledDateUTC datetime2 NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'LastPaymentFailureDateUTC')
    ALTER TABLE dbo.UserSubscription ADD LastPaymentFailureDateUTC datetime2 NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'dbo.UserSubscription') AND name = N'LastStripeEventId')
    ALTER TABLE dbo.UserSubscription ADD LastStripeEventId nvarchar(100) NULL;
GO

IF OBJECT_ID(N'dbo.StripeWebhookEvent', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.StripeWebhookEvent
    (
        StripeWebhookEventID bigint IDENTITY(1,1) NOT NULL CONSTRAINT PK_StripeWebhookEvent PRIMARY KEY,
        StripeEventId nvarchar(100) NOT NULL,
        EventType nvarchar(100) NOT NULL,
        ReceivedDateUTC datetime2 NOT NULL CONSTRAINT DF_StripeWebhookEvent_ReceivedDateUTC DEFAULT SYSUTCDATETIME(),
        ProcessedDateUTC datetime2 NULL,
        ProcessingStatus nvarchar(50) NOT NULL CONSTRAINT DF_StripeWebhookEvent_ProcessingStatus DEFAULT N'Received',
        ErrorMessage nvarchar(1000) NULL,
        CONSTRAINT UX_StripeWebhookEvent_EventId UNIQUE (StripeEventId)
    );
END;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_UserSubscription_StripeSubscriptionId' AND object_id = OBJECT_ID(N'dbo.UserSubscription'))
    CREATE INDEX IX_UserSubscription_StripeSubscriptionId ON dbo.UserSubscription(StripeSubscriptionId) WHERE StripeSubscriptionId IS NOT NULL;
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_UserSubscription_StripeCustomerId' AND object_id = OBJECT_ID(N'dbo.UserSubscription'))
    CREATE INDEX IX_UserSubscription_StripeCustomerId ON dbo.UserSubscription(StripeCustomerId) WHERE StripeCustomerId IS NOT NULL;
GO

UPDATE dbo.SubscriptionLevel
SET RequiresStripeSubscription = CASE WHEN Name = N'DraftDesk' THEN 0 ELSE 1 END,
    StripeMonthlyPriceId = CASE Name
        WHEN N'WritingRoom' THEN N'price_1TffeZIH8aCkpHgj4AlC7Atv'
        WHEN N'StoryForge' THEN N'price_1TffdJIH8aCkpHgjvQfV7heX'
        WHEN N'AuthorStudio' THEN N'price_1TffbaIH8aCkpHgjKFLoaHMJ'
        ELSE NULL
    END,
    StripeAnnualPriceId = CASE Name
        WHEN N'WritingRoom' THEN N'price_1Tffe8IH8aCkpHgj25QRMu4t'
        WHEN N'StoryForge' THEN N'price_1TffccIH8aCkpHgjXlSwB4A1'
        WHEN N'AuthorStudio' THEN N'price_1TffaRIH8aCkpHgjIoQqgwBH'
        ELSE NULL
    END,
    ModifiedDateUTC = SYSUTCDATETIME();
GO

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

    SELECT SubscriptionLevelID, Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook,
        MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive,
        SortOrder, CreatedDateUTC, ModifiedDateUTC, StripeMonthlyPriceId, StripeAnnualPriceId,
        RequiresStripeSubscription
    FROM dbo.SubscriptionLevel
    WHERE IsActive = 1
    ORDER BY SortOrder, DisplayName;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SubscriptionLevel_Get
    @SubscriptionLevelID int
AS
BEGIN
    SET NOCOUNT ON;

    SELECT SubscriptionLevelID, Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook,
        MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive,
        SortOrder, CreatedDateUTC, ModifiedDateUTC, StripeMonthlyPriceId, StripeAnnualPriceId,
        RequiresStripeSubscription
    FROM dbo.SubscriptionLevel
    WHERE SubscriptionLevelID = @SubscriptionLevelID;
END;
GO

CREATE OR ALTER PROCEDURE dbo.SubscriptionLevel_GetByStripePrice
    @StripePriceId nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT SubscriptionLevelID, Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook,
        MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive,
        SortOrder, CreatedDateUTC, ModifiedDateUTC, StripeMonthlyPriceId, StripeAnnualPriceId,
        RequiresStripeSubscription,
        CASE
            WHEN StripeMonthlyPriceId = @StripePriceId THEN N'Monthly'
            WHEN StripeAnnualPriceId = @StripePriceId THEN N'Annual'
            ELSE NULL
        END AS BillingInterval
    FROM dbo.SubscriptionLevel
    WHERE IsActive = 1
        AND RequiresStripeSubscription = 1
        AND (StripeMonthlyPriceId = @StripePriceId OR StripeAnnualPriceId = @StripePriceId);
END;
GO

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

    SELECT us.UserSubscriptionID, us.UserID, us.SubscriptionLevelID, us.StartDateUTC, us.EndDateUTC,
        us.IsActive, us.IsTrial, us.TrialExpiryDateUTC, us.CreatedDateUTC, us.ModifiedDateUTC,
        us.StripeCustomerId, us.StripeSubscriptionId, us.StripePriceId, us.BillingInterval, us.StripeStatus,
        us.CurrentPeriodStartUTC, us.CurrentPeriodEndUTC, us.CancelAtPeriodEnd, us.CancelledDateUTC,
        us.LastPaymentFailureDateUTC, us.LastStripeEventId,
        sl.Name, sl.DisplayName, sl.Description, sl.MaxBooks, sl.MaxChaptersPerBook,
        sl.MaxScenesPerBook, sl.MaxCharactersPerProject, sl.MaxStorageMB, sl.MaxCollaborators,
        sl.IsActive AS SubscriptionLevelIsActive, sl.SortOrder, sl.StripeMonthlyPriceId,
        sl.StripeAnnualPriceId, sl.RequiresStripeSubscription
    FROM dbo.UserSubscription us
    INNER JOIN dbo.SubscriptionLevel sl ON sl.SubscriptionLevelID = us.SubscriptionLevelID
    WHERE us.UserID = @UserID
        AND us.IsActive = 1
        AND (us.EndDateUTC IS NULL OR us.EndDateUTC > SYSUTCDATETIME());
END;
GO

CREATE OR ALTER PROCEDURE dbo.UserSubscription_SetStripeCustomer
    @UserID int,
    @StripeCustomerId nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.UserSubscription
    SET StripeCustomerId = @StripeCustomerId,
        ModifiedDateUTC = SYSUTCDATETIME()
    WHERE UserID = @UserID
        AND IsActive = 1;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StripeWebhookEvent_TryBegin
    @StripeEventId nvarchar(100),
    @EventType nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;

    IF EXISTS (SELECT 1 FROM dbo.StripeWebhookEvent WHERE StripeEventId = @StripeEventId)
    BEGIN
        SELECT CAST(0 AS bit) AS ShouldProcess;
        RETURN;
    END;

    INSERT dbo.StripeWebhookEvent (StripeEventId, EventType)
    VALUES (@StripeEventId, @EventType);

    SELECT CAST(1 AS bit) AS ShouldProcess;
END;
GO

CREATE OR ALTER PROCEDURE dbo.StripeWebhookEvent_Complete
    @StripeEventId nvarchar(100),
    @ProcessingStatus nvarchar(50),
    @ErrorMessage nvarchar(1000) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.StripeWebhookEvent
    SET ProcessingStatus = @ProcessingStatus,
        ProcessedDateUTC = SYSUTCDATETIME(),
        ErrorMessage = @ErrorMessage
    WHERE StripeEventId = @StripeEventId;
END;
GO

CREATE OR ALTER PROCEDURE dbo.UserSubscription_ApplyStripeState
    @UserID int = NULL,
    @SubscriptionLevelID int = NULL,
    @StripeCustomerId nvarchar(100),
    @StripeSubscriptionId nvarchar(100),
    @StripePriceId nvarchar(100),
    @BillingInterval nvarchar(20),
    @StripeStatus nvarchar(50),
    @CurrentPeriodStartUTC datetime2 = NULL,
    @CurrentPeriodEndUTC datetime2 = NULL,
    @CancelAtPeriodEnd bit = 0,
    @LastStripeEventId nvarchar(100) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    IF @SubscriptionLevelID IS NULL
        SELECT @SubscriptionLevelID = SubscriptionLevelID
        FROM dbo.SubscriptionLevel
        WHERE IsActive = 1
            AND (StripeMonthlyPriceId = @StripePriceId OR StripeAnnualPriceId = @StripePriceId);

    IF @BillingInterval IS NULL
        SELECT @BillingInterval = CASE
            WHEN StripeMonthlyPriceId = @StripePriceId THEN N'Monthly'
            WHEN StripeAnnualPriceId = @StripePriceId THEN N'Annual'
            ELSE NULL
        END
        FROM dbo.SubscriptionLevel
        WHERE SubscriptionLevelID = @SubscriptionLevelID;

    IF @UserID IS NULL
        SELECT TOP (1) @UserID = UserID
        FROM dbo.UserSubscription
        WHERE StripeSubscriptionId = @StripeSubscriptionId
            OR StripeCustomerId = @StripeCustomerId
        ORDER BY IsActive DESC, ModifiedDateUTC DESC;

    IF @UserID IS NULL OR @SubscriptionLevelID IS NULL
        RETURN;

    DECLARE @ExistingSubscriptionID int;
    SELECT TOP (1) @ExistingSubscriptionID = UserSubscriptionID
    FROM dbo.UserSubscription
    WHERE UserID = @UserID
        AND IsActive = 1
    ORDER BY UserSubscriptionID DESC;

    IF @ExistingSubscriptionID IS NULL
    BEGIN
        INSERT dbo.UserSubscription
        (
            UserID, SubscriptionLevelID, StartDateUTC, EndDateUTC, IsActive, IsTrial, TrialExpiryDateUTC,
            StripeCustomerId, StripeSubscriptionId, StripePriceId, BillingInterval, StripeStatus,
            CurrentPeriodStartUTC, CurrentPeriodEndUTC, CancelAtPeriodEnd, LastStripeEventId
        )
        VALUES
        (
            @UserID, @SubscriptionLevelID, COALESCE(@CurrentPeriodStartUTC, SYSUTCDATETIME()), NULL, 1, 0, NULL,
            @StripeCustomerId, @StripeSubscriptionId, @StripePriceId, @BillingInterval, @StripeStatus,
            @CurrentPeriodStartUTC, @CurrentPeriodEndUTC, @CancelAtPeriodEnd, @LastStripeEventId
        );
    END
    ELSE
    BEGIN
        UPDATE dbo.UserSubscription
        SET SubscriptionLevelID = @SubscriptionLevelID,
            EndDateUTC = NULL,
            IsActive = 1,
            IsTrial = 0,
            TrialExpiryDateUTC = NULL,
            StripeCustomerId = @StripeCustomerId,
            StripeSubscriptionId = @StripeSubscriptionId,
            StripePriceId = @StripePriceId,
            BillingInterval = @BillingInterval,
            StripeStatus = @StripeStatus,
            CurrentPeriodStartUTC = @CurrentPeriodStartUTC,
            CurrentPeriodEndUTC = @CurrentPeriodEndUTC,
            CancelAtPeriodEnd = @CancelAtPeriodEnd,
            CancelledDateUTC = CASE WHEN @StripeStatus = N'canceled' THEN COALESCE(CancelledDateUTC, SYSUTCDATETIME()) ELSE NULL END,
            LastPaymentFailureDateUTC = CASE WHEN @StripeStatus IN (N'active', N'trialing') THEN NULL ELSE LastPaymentFailureDateUTC END,
            LastStripeEventId = @LastStripeEventId,
            ModifiedDateUTC = SYSUTCDATETIME()
        WHERE UserSubscriptionID = @ExistingSubscriptionID;
    END;
END;
GO

CREATE OR ALTER PROCEDURE dbo.UserSubscription_DowngradeToDraftDesk
    @StripeCustomerId nvarchar(100) = NULL,
    @StripeSubscriptionId nvarchar(100) = NULL,
    @LastStripeEventId nvarchar(100) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @DraftDeskID int;
    SELECT @DraftDeskID = SubscriptionLevelID FROM dbo.SubscriptionLevel WHERE Name = N'DraftDesk';

    IF @DraftDeskID IS NULL
        RETURN;

    UPDATE dbo.UserSubscription
    SET SubscriptionLevelID = @DraftDeskID,
        EndDateUTC = NULL,
        IsActive = 1,
        IsTrial = 0,
        TrialExpiryDateUTC = NULL,
        StripeStatus = N'canceled',
        CancelAtPeriodEnd = 0,
        CancelledDateUTC = COALESCE(CancelledDateUTC, SYSUTCDATETIME()),
        LastStripeEventId = @LastStripeEventId,
        ModifiedDateUTC = SYSUTCDATETIME()
    WHERE (@StripeSubscriptionId IS NOT NULL AND StripeSubscriptionId = @StripeSubscriptionId)
        OR (@StripeCustomerId IS NOT NULL AND StripeCustomerId = @StripeCustomerId);
END;
GO

CREATE OR ALTER PROCEDURE dbo.UserSubscription_RecordPaymentFailure
    @StripeCustomerId nvarchar(100) = NULL,
    @StripeSubscriptionId nvarchar(100) = NULL,
    @LastStripeEventId nvarchar(100) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.UserSubscription
    SET LastPaymentFailureDateUTC = SYSUTCDATETIME(),
        LastStripeEventId = @LastStripeEventId,
        ModifiedDateUTC = SYSUTCDATETIME()
    WHERE (@StripeSubscriptionId IS NOT NULL AND StripeSubscriptionId = @StripeSubscriptionId)
        OR (@StripeCustomerId IS NOT NULL AND StripeCustomerId = @StripeCustomerId);
END;
GO

CREATE OR ALTER PROCEDURE dbo.UserSubscription_ClearPaymentFailure
    @StripeCustomerId nvarchar(100) = NULL,
    @StripeSubscriptionId nvarchar(100) = NULL,
    @LastStripeEventId nvarchar(100) = NULL
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE dbo.UserSubscription
    SET LastPaymentFailureDateUTC = NULL,
        LastStripeEventId = @LastStripeEventId,
        ModifiedDateUTC = SYSUTCDATETIME()
    WHERE (@StripeSubscriptionId IS NOT NULL AND StripeSubscriptionId = @StripeSubscriptionId)
        OR (@StripeCustomerId IS NOT NULL AND StripeCustomerId = @StripeCustomerId);
END;
GO
