/*
================================================================================
FixBulkCreditPayoutsWrongBalance.sql
================================================================================
شناسایی لاگ اشتباه BulkCredit در UserWalletHistories:

  RefrenceId IN (payoutهای BulkCredit شده)
  AND CreatedBy <> 'SP'          -- لاگ SP = NetworkBalance درست، حذف نشود
  AND ChangeValue > 0            -- واریز اشتباه به Balance
  AND ChangeDiscountValue <= 0

اصلاح:
  - کسر ChangeValue از Balance همان WalletId
  - حذف رکوردهای UserWalletHistories اشتباه

  @DryRun = 1  → فقط گزارش
  @DryRun = 0  → اعمال fix
================================================================================
*/

SET NOCOUNT ON;
SET XACT_ABORT ON;

DECLARE @DryRun    BIT = 1;
DECLARE @WeeksBack INT = 4;
DECLARE @SinceDate DATETIME = DATEADD(WEEK, -@WeeksBack, GETUTCDATE());

-- کاربرانی که fix برایشان اعمال می‌شود حتی اگر Balance منفی شود
DECLARE @AllowNegativeUserIds TABLE (UserId BIGINT PRIMARY KEY);
INSERT INTO @AllowNegativeUserIds (UserId) VALUES (106);  -- مهرداد شجاعی

PRINT CONCAT('DryRun = ', @DryRun, ' | WeeksBack = ', @WeeksBack);
PRINT '';

-- payoutهای BulkCredit شده (از CommissionPayoutHistories)
;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0
      AND cph.Action = 1
      AND cph.Created >= @SinceDate
      AND (
          cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%'
          OR cph.Reason LIKE N'%واریز دسته%جمعی%'
      )
),
WrongWalletLogs AS (
    SELECT
        wh.Id           AS WalletHistoryId,
        wh.WalletId,
        wh.RefrenceId   AS PayoutId,
        p.UserId,
        wh.ChangeValue  AS WrongBalanceCredit,
        wh.Created      AS WrongCreditAt,
        wh.CreatedBy
    FROM CMS.UserWalletHistories wh
    INNER JOIN CMS.UserCommissionPayouts p
        ON p.Id = wh.RefrenceId AND p.IsDeleted = 0
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0
)

-- 1) خلاصه
SELECT
    (SELECT COUNT(*) FROM BulkCreditedPayoutIds)              AS BulkCreditedPayoutCount,
    (SELECT COUNT(DISTINCT p.UserId)
     FROM CMS.UserCommissionPayouts p
     WHERE p.Id IN (SELECT PayoutId FROM BulkCreditedPayoutIds)) AS BulkCreditedUserCount,
    (SELECT COUNT(*) FROM WrongWalletLogs)                    AS WrongWalletHistoryCount,
    (SELECT COUNT(DISTINCT UserId) FROM WrongWalletLogs)      AS AffectedUserCount,
    (SELECT ISNULL(SUM(WrongBalanceCredit), 0) FROM WrongWalletLogs) AS TotalWrongBalanceCredit;

PRINT '';
PRINT '--- PayoutIdهای BulkCredit (برای مقایسه با لیست دستی) ---';
SELECT PayoutId FROM (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
) x ORDER BY PayoutId;

PRINT '';
PRINT '--- UserWalletHistories اشتباه ---';

;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
)
SELECT
    wh.Id AS WalletHistoryId,
    wh.RefrenceId AS PayoutId,
    p.UserId,
    u.Mobile,
    CONCAT(u.FirstName, N' ', u.LastName) AS FullName,
    p.WeekDefinitionId,
    p.TotalAmount AS PayoutAmount,
    wh.ChangeValue AS WrongBalanceCredit,
    uw.Balance AS CurrentBalance,
    uw.NetworkBalance,
    wh.Created AS WrongCreditAt,
    wh.CreatedBy
FROM CMS.UserWalletHistories wh
INNER JOIN CMS.UserCommissionPayouts p ON p.Id = wh.RefrenceId AND p.IsDeleted = 0
INNER JOIN CMS.UserWallets uw ON uw.Id = wh.WalletId AND uw.IsDeleted = 0
INNER JOIN CMS.Users u ON u.Id = p.UserId AND u.IsDeleted = 0
WHERE wh.IsDeleted = 0
  AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
  AND wh.CreatedBy <> N'SP'
  AND wh.ChangeValue > 0
  AND wh.ChangeDiscountValue <= 0
ORDER BY p.UserId, wh.RefrenceId;

PRINT '';
PRINT '--- خلاصه به تفکیک کاربر ---';

;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
),
WrongWalletLogs AS (
    SELECT wh.Id AS WalletHistoryId, wh.WalletId, wh.RefrenceId AS PayoutId,
           p.UserId, wh.ChangeValue AS WrongBalanceCredit
    FROM CMS.UserWalletHistories wh
    INNER JOIN CMS.UserCommissionPayouts p ON p.Id = wh.RefrenceId AND p.IsDeleted = 0
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0
)
SELECT
    w.UserId,
    u.Mobile,
    CONCAT(u.FirstName, N' ', u.LastName) AS FullName,
    COUNT(w.WalletHistoryId) AS WrongHistoryCount,
    COUNT(DISTINCT w.PayoutId) AS AffectedPayoutCount,
    SUM(w.WrongBalanceCredit) AS TotalWrongCredit,
    uw.Balance AS CurrentBalance,
    uw.Balance - SUM(w.WrongBalanceCredit) AS BalanceAfterFix,
    CASE
        WHEN w.UserId IN (SELECT UserId FROM @AllowNegativeUserIds)
             AND uw.Balance < SUM(w.WrongBalanceCredit) THEN N'OK — منفی مجاز'
        WHEN uw.Balance < SUM(w.WrongBalanceCredit) THEN N'⚠ موجودی کافی نیست'
        ELSE N'OK'
    END AS FixStatus
FROM WrongWalletLogs w
INNER JOIN CMS.Users u ON u.Id = w.UserId AND u.IsDeleted = 0
INNER JOIN CMS.UserWallets uw ON uw.Id = w.WalletId AND uw.IsDeleted = 0
GROUP BY w.UserId, u.Mobile, u.FirstName, u.LastName, uw.Id, uw.Balance
ORDER BY TotalWrongCredit DESC;

PRINT '';
PRINT '--- blockers (به‌جز کاربران با منفی مجاز) ---';

;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
),
WrongPerWallet AS (
    SELECT wh.WalletId, SUM(wh.ChangeValue) AS TotalWrongCredit
    FROM CMS.UserWalletHistories wh
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0
    GROUP BY wh.WalletId
)
SELECT uw.UserId, u.Mobile, uw.Balance AS CurrentBalance,
       w.TotalWrongCredit, uw.Balance - w.TotalWrongCredit AS BalanceAfterFix
FROM WrongPerWallet w
INNER JOIN CMS.UserWallets uw ON uw.Id = w.WalletId AND uw.IsDeleted = 0
INNER JOIN CMS.Users u ON u.Id = uw.UserId AND u.IsDeleted = 0
WHERE uw.Balance < w.TotalWrongCredit
  AND uw.UserId NOT IN (SELECT UserId FROM @AllowNegativeUserIds);

PRINT '';
PRINT '--- منفی مجاز (fix اعمال می‌شود) ---';

;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
),
WrongPerWallet AS (
    SELECT wh.WalletId, SUM(wh.ChangeValue) AS TotalWrongCredit
    FROM CMS.UserWalletHistories wh
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0
    GROUP BY wh.WalletId
)
SELECT uw.UserId, u.Mobile, uw.Balance AS CurrentBalance,
       w.TotalWrongCredit, uw.Balance - w.TotalWrongCredit AS BalanceAfterFix
FROM WrongPerWallet w
INNER JOIN CMS.UserWallets uw ON uw.Id = w.WalletId AND uw.IsDeleted = 0
INNER JOIN CMS.Users u ON u.Id = uw.UserId AND u.IsDeleted = 0
WHERE uw.Balance < w.TotalWrongCredit
  AND uw.UserId IN (SELECT UserId FROM @AllowNegativeUserIds);

-- ── اعمال fix ──
IF @DryRun = 1
BEGIN
    PRINT '';
    PRINT 'DryRun — تغییری اعمال نشد. برای fix: @DryRun = 0';
    RETURN;
END

DECLARE @BlockerCount INT;
DECLARE @FixedWallets INT;
DECLARE @DeletedHistories INT;
DECLARE @TotalReverted BIGINT;
DECLARE @ErrMsg NVARCHAR(4000);

;WITH BulkCreditedPayoutIds AS (
    SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
    FROM CMS.CommissionPayoutHistories cph
    WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
      AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
),
WrongPerWallet AS (
    SELECT wh.WalletId, SUM(wh.ChangeValue) AS TotalWrongCredit
    FROM CMS.UserWalletHistories wh
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0
    GROUP BY wh.WalletId
)
SELECT @BlockerCount = COUNT(*)
FROM WrongPerWallet w
INNER JOIN CMS.UserWallets uw ON uw.Id = w.WalletId AND uw.IsDeleted = 0
WHERE uw.Balance < w.TotalWrongCredit
  AND uw.UserId NOT IN (SELECT UserId FROM @AllowNegativeUserIds);

IF @BlockerCount > 0
BEGIN
    RAISERROR(N'%d کیف پول Balance منفی می‌شود — fix متوقف شد.', 16, 1, @BlockerCount);
    RETURN;
END

BEGIN TRY
    BEGIN TRANSACTION;

    ;WITH BulkCreditedPayoutIds AS (
        SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
        FROM CMS.CommissionPayoutHistories cph
        WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
          AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
    ),
    WrongPerWallet AS (
        SELECT wh.WalletId, SUM(wh.ChangeValue) AS TotalWrongCredit
        FROM CMS.UserWalletHistories wh
        WHERE wh.IsDeleted = 0
          AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
          AND wh.CreatedBy <> N'SP'
          AND wh.ChangeValue > 0
          AND wh.ChangeDiscountValue <= 0
        GROUP BY wh.WalletId
    )
    UPDATE uw
    SET uw.Balance = uw.Balance - w.TotalWrongCredit,
        uw.LastModified = GETUTCDATE(),
        uw.LastModifiedBy = N'FixBulkCreditPayoutsWrongBalance'
    FROM CMS.UserWallets uw
    INNER JOIN WrongPerWallet w ON w.WalletId = uw.Id
    WHERE uw.IsDeleted = 0;

    SET @FixedWallets = @@ROWCOUNT;

    ;WITH BulkCreditedPayoutIds AS (
        SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
        FROM CMS.CommissionPayoutHistories cph
        WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
          AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
    )
    SELECT @TotalReverted = ISNULL(SUM(wh.ChangeValue), 0)
    FROM CMS.UserWalletHistories wh
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0;

    ;WITH BulkCreditedPayoutIds AS (
        SELECT DISTINCT cph.UserCommissionPayoutId AS PayoutId
        FROM CMS.CommissionPayoutHistories cph
        WHERE cph.IsDeleted = 0 AND cph.Action = 1 AND cph.Created >= @SinceDate
          AND (cph.Reason LIKE N'%تایید پرداخت دسته%جمعی%' OR cph.Reason LIKE N'%واریز دسته%جمعی%')
    )
    DELETE wh
    FROM CMS.UserWalletHistories wh
    WHERE wh.IsDeleted = 0
      AND wh.RefrenceId IN (SELECT PayoutId FROM BulkCreditedPayoutIds)
      AND wh.CreatedBy <> N'SP'
      AND wh.ChangeValue > 0
      AND wh.ChangeDiscountValue <= 0;

    SET @DeletedHistories = @@ROWCOUNT;

    COMMIT TRANSACTION;

    PRINT CONCAT('کیف پول اصلاح‌شده: ', @FixedWallets);
    PRINT CONCAT('لاگ حذف‌شده: ', @DeletedHistories);
    PRINT CONCAT('مجموع برگردانده‌شده: ', @TotalReverted);
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
    SET @ErrMsg = ERROR_MESSAGE();
    RAISERROR(@ErrMsg, 16, 1);
END CATCH;

GO

/*
-- کوئری ساده دستی (معادل همین منطق با لیست PayoutId ثابت):

SELECT *
FROM CMS.UserWalletHistories
WHERE RefrenceId IN (
    115,116,117,118,119,125,126,127,128,129,130,131,132,133,134,
    135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,
    150,151,152,153
)
AND CreatedBy <> N'SP'
AND ChangeValue > 0
AND ChangeDiscountValue <= 0;
*/
