-- =============================================
-- Stored Procedure: sp_CalculateWeeklyCommissionPool
-- Description: محاسبه استخر کمیسیون هفتگی و توزیع بین کاربران
-- Author: System
-- Created: 2025-12-19
-- Updated: Q29 — اضافه کردن @PackageId، fix فیلتر pool، مدیریت pool خالی
-- =============================================

CREATE OR ALTER PROCEDURE [CMS].[sp_CalculateWeeklyCommissionPool]
    @WeekDefinitionId BIGINT,
    @PackageId BIGINT,           -- هر بار به ازای یک پکیج اجرا می‌شود
    @ForceRecalculate BIT = 0,
    @PoolId BIGINT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @TotalPoolAmount BIGINT = 0;
    DECLARE @TotalBalances INT;
    DECLARE @ValuePerBalance BIGINT;
    DECLARE @CalculatedAt DATETIME = GETDATE();

    BEGIN TRY
        BEGIN TRANSACTION;

        -- =============================================
        -- 1. پیدا کردن Pool هفته (فیلتر بر اساس PackageId)
        -- =============================================
        SELECT @PoolId = Id, @TotalPoolAmount = TotalPoolAmount
        FROM CMS.WeeklyCommissionPools
        WHERE WeekDefinitionId = @WeekDefinitionId AND PackageId = @PackageId;

        -- اگر Pool وجود ندارد (هیچ فعال‌سازی در این هفته نبوده)، یک رکورد خالی ایجاد می‌کنیم
        IF @PoolId IS NULL
        BEGIN
            INSERT INTO CMS.WeeklyCommissionPools (
                WeekDefinitionId, PackageId, TotalPoolAmount, TotalBalances,
                ValuePerBalance, IsCalculated, CalculatedAt,
                IsDeleted, Created, CreatedBy, LastModified, LastModifiedBy
            ) VALUES (
                @WeekDefinitionId, @PackageId, 0, 0, 0, 0, NULL,
                0, @CalculatedAt, 'SP', @CalculatedAt, 'SP'
            );
            SET @PoolId = SCOPE_IDENTITY();
            SET @TotalPoolAmount = 0;
        END

        -- =============================================
        -- 2. بررسی محاسبات قبلی (بر اساس همین Pool نه کل هفته)
        -- =============================================
        IF EXISTS (SELECT 1 FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId)
        BEGIN
            IF @ForceRecalculate = 0
            BEGIN
                SET @ErrorMessage = N'کمیسیون هفته ' + CAST(@WeekDefinitionId AS NVARCHAR(20))
                    + N' (پکیج ' + CAST(@PackageId AS NVARCHAR(20)) + N') قبلاً محاسبه شده است. برای محاسبه مجدد از ForceRecalculate استفاده کنید';
                RAISERROR(@ErrorMessage, 16, 1);
                RETURN;
            END

            -- =============================================
            -- 3. Revert کیف پول‌ها (در صورت ForceRecalculate، فقط پرداخت‌های این Pool)
            -- =============================================

            -- کم کردن مقادیر قبلی از NetworkBalance
            UPDATE uw
            SET uw.NetworkBalance = uw.NetworkBalance - ISNULL(
                (SELECT SUM(wl.ChangeNerworkValue)
                 FROM CMS.UserWalletChangeLogs wl
                 WHERE wl.WalletId = uw.Id
                 AND wl.RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId)
                ), 0)
            FROM CMS.UserWallets uw
            WHERE uw.Id IN (
                SELECT DISTINCT wl.WalletId
                FROM CMS.UserWalletChangeLogs wl
                WHERE wl.RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId)
            );

            -- حذف لاگ‌های تغییرات قبلی
            DELETE FROM CMS.UserWalletChangeLogs
            WHERE RefrenceId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId);

            -- حذف تاریخچه پرداخت
            DELETE FROM CMS.CommissionPayoutHistories
            WHERE UserCommissionPayoutId IN (SELECT Id FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId);

            -- حذف پرداخت‌های قبلی این Pool
            DELETE FROM CMS.UserCommissionPayouts WHERE WeeklyPoolId = @PoolId;

            -- Reset وضعیت Pool
            UPDATE CMS.WeeklyCommissionPools
            SET IsCalculated = 0
            WHERE Id = @PoolId;
        END

        -- =============================================
        -- 4. بررسی وجود تعادل‌های هفتگی
        -- =============================================
        IF NOT EXISTS (SELECT 1 FROM CMS.NetworkWeeklyBalances WHERE WeekDefinitionId = @WeekDefinitionId)
        BEGIN
            -- بالانسی محاسبه نشده — pool را به عنوان "محاسبه شده بدون پرداخت" علامت می‌زنیم
            UPDATE CMS.WeeklyCommissionPools
            SET IsCalculated = 1, CalculatedAt = @CalculatedAt
            WHERE Id = @PoolId;

            COMMIT TRANSACTION;
            RETURN;
        END

        -- =============================================
        -- 5. محاسبه مجموع تعادل‌ها
        -- =============================================
        SELECT @TotalBalances = SUM(TotalBalances)
        FROM CMS.NetworkWeeklyBalances
        WHERE WeekDefinitionId = @WeekDefinitionId AND TotalBalances > 0;

        IF @TotalBalances IS NULL OR @TotalBalances = 0
        BEGIN
            -- هیچ تعادلی برای توزیع وجود ندارد — pool محاسبه شده اما پرداختی ندارد
            UPDATE CMS.WeeklyCommissionPools
            SET IsCalculated = 1, CalculatedAt = @CalculatedAt
            WHERE Id = @PoolId;

            COMMIT TRANSACTION;
            RETURN;
        END

        -- =============================================
        -- 6. محاسبه ارزش هر تعادل
        -- =============================================
        SET @ValuePerBalance = @TotalPoolAmount / @TotalBalances;

        -- =============================================
        -- 7. ایجاد پرداخت برای هر کاربر
        -- =============================================
        INSERT INTO CMS.UserCommissionPayouts (
            UserId,
            WeekDefinitionId,
            WeeklyPoolId,
            BalancesEarned,
            ValuePerBalance,
            TotalAmount,
            Status,
            PaidAt,
            IsDeleted,
            Created,
            CreatedBy,
            LastModified,
            LastModifiedBy
        )
        SELECT
            nb.UserId,
            @WeekDefinitionId,
            @PoolId,
            nb.TotalBalances,
            @ValuePerBalance,
            nb.TotalBalances * @ValuePerBalance,
            0,    -- Status: Pending
            NULL, -- PaidAt
            0,    -- IsDeleted
            @CalculatedAt,
            'SP',
            @CalculatedAt,
            'SP'
        FROM CMS.NetworkWeeklyBalances nb
        WHERE nb.WeekDefinitionId = @WeekDefinitionId AND nb.TotalBalances > 0;

        -- =============================================
        -- 8. ثبت تاریخچه پرداخت
        -- =============================================
        INSERT INTO CMS.CommissionPayoutHistories (
            UserCommissionPayoutId,
            UserId,
            WeekDefinitionId,
            AmountBefore,
            AmountAfter,
            OldStatus,
            NewStatus,
            Action,
            PerformedBy,
            Reason,
            IsDeleted,
            Created,
            CreatedBy,
            LastModified,
            LastModifiedBy
        )
        SELECT
            cp.Id,
            cp.UserId,
            @WeekDefinitionId,
            0,
            cp.TotalAmount,
            0,               -- OldStatus: Pending
            0,               -- NewStatus: Pending
            0,               -- Action: Created
            'SP',
            N'محاسبه اولیه توسط SP',
            0,
            @CalculatedAt,
            'SP',
            @CalculatedAt,
            'SP'
        FROM CMS.UserCommissionPayouts cp
        WHERE cp.WeeklyPoolId = @PoolId;

        -- =============================================
        -- 9. شارژ کیف پول کاربران
        -- =============================================

        -- بروزرسانی NetworkBalance
        UPDATE uw
        SET uw.NetworkBalance = uw.NetworkBalance + cp.TotalAmount
        FROM CMS.UserWallets uw
        INNER JOIN CMS.UserCommissionPayouts cp ON cp.UserId = uw.UserId
        WHERE cp.WeeklyPoolId = @PoolId;

        -- ثبت لاگ تغییرات کیف پول
        INSERT INTO CMS.UserWalletChangeLogs (
            WalletId,
            CurrentBalance,
            ChangeValue,
            CurrentNetworkBalance,
            ChangeNerworkValue,
            CurrentDiscountBalance,
            ChangeDiscountValue,
            IsIncrease,
            RefrenceId,
            IsDeleted,
            Created,
            CreatedBy,
            LastModified,
            LastModifiedBy
        )
        SELECT
            uw.Id,
            uw.Balance,
            0,                  -- ChangeValue (no change to main balance)
            uw.NetworkBalance,  -- CurrentNetworkBalance (after update)
            cp.TotalAmount,     -- ChangeNerworkValue
            uw.DiscountBalance,
            0,                  -- ChangeDiscountValue
            1,                  -- IsIncrease: true
            cp.Id,              -- RefrenceId: PayoutId
            0,
            @CalculatedAt,
            'SP',
            @CalculatedAt,
            'SP'
        FROM CMS.UserCommissionPayouts cp
        INNER JOIN CMS.UserWallets uw ON uw.UserId = cp.UserId
        WHERE cp.WeeklyPoolId = @PoolId;

        -- =============================================
        -- 10. بروزرسانی Pool
        -- =============================================
        UPDATE CMS.WeeklyCommissionPools 
        SET 
            IsCalculated = 1, 
            CalculatedAt = @CalculatedAt,
            TotalBalances = @TotalBalances,
            ValuePerBalance = @ValuePerBalance,
            LastModified = @CalculatedAt,
            LastModifiedBy = 'SP'
        WHERE Id = @PoolId;

        COMMIT TRANSACTION;

    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;

        SET @ErrorMessage = ERROR_MESSAGE();
        RAISERROR(@ErrorMessage, 16, 1);
    END CATCH
END
GO
