/*
  One-time cleanup: ClubMemberships without a successful UserPackagePurchases row.

  Goal after this script:
    every non-deleted ClubMembership user has >= 1 successful UPP
    (TransactionId IS NULL OR Transaction.PaymentStatus = 0 / Success)

  Priority for missing rows:
    1) ManualPayments Approved + successful Transaction  -> reuse same TransactionId
       PurchaseMethod = Manual (3)
    2) else ClubMembershipCycles / membership dates     -> create synthetic Success Transaction + UPP
       PurchaseMethod priority:
         Cycle.PurchaseMethod (if not None)
         -> ClubMembership.PurchaseMethod (if not None)
         -> Users.PackagePurchaseMethod (if not None)
         -> Manual (3) as last resort

  Safe to re-run (skips users who already have a successful UPP).

  Run against CMS database once, then verify Orphans left = 0.
*/

SET NOCOUNT ON;
SET XACT_ABORT ON;

BEGIN TRAN;

------------------------------------------------------------
-- 1) From ManualPayments (reuse existing Success transaction)
------------------------------------------------------------
;WITH OrphanClubUsers AS (
    SELECT m.UserId,
           COALESCE(NULLIF(m.LastPackageId, 0), NULLIF(m.FirstPackageId, 0)) AS PackageIdHint
    FROM CMS.ClubMemberships m
    WHERE m.IsDeleted = 0
      AND NOT EXISTS (
          SELECT 1
          FROM CMS.UserPackagePurchases upp
          LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
          WHERE upp.UserId = m.UserId
            AND upp.IsDeleted = 0
            AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
      )
),
BestManual AS (
    SELECT mp.UserId,
           mp.Id AS ManualPaymentId,
           mp.Amount,
           mp.TransactionId,
           COALESCE(mp.ApprovedAt, mp.Created) AS PurchasedAt,
           ROW_NUMBER() OVER (
               PARTITION BY mp.UserId
               ORDER BY COALESCE(mp.ApprovedAt, mp.Created) DESC, mp.Id DESC
           ) AS rn
    FROM CMS.ManualPayments mp
    INNER JOIN CMS.Transactions t ON t.Id = mp.TransactionId AND t.IsDeleted = 0 AND t.PaymentStatus = 0
    WHERE mp.IsDeleted = 0
      AND mp.Status = 1 -- Approved
      AND mp.TransactionId IS NOT NULL
),
BasePkg AS (
    SELECT TOP (1) Id AS PackageId, Price
    FROM CMS.Packages
    WHERE IsDeleted = 0 AND IsBasePackage = 1
    ORDER BY Id
)
INSERT INTO CMS.UserPackagePurchases
(
    UserId, PackageId, PurchaseMethod, PurchasedAt, Amount,
    OrderId, TransactionId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
)
SELECT
    o.UserId,
    COALESCE(o.PackageIdHint, b.PackageId),
    3, -- Manual
    bm.PurchasedAt,
    bm.Amount,
    NULL,
    bm.TransactionId,
    SYSUTCDATETIME(),
    NULL,
    SYSUTCDATETIME(),
    NULL,
    0
FROM OrphanClubUsers o
INNER JOIN BestManual bm ON bm.UserId = o.UserId AND bm.rn = 1
CROSS JOIN BasePkg b
WHERE COALESCE(o.PackageIdHint, b.PackageId) IS NOT NULL;

DECLARE @FromManual INT = @@ROWCOUNT;
PRINT CONCAT('Inserted from ManualPayments: ', @FromManual);

------------------------------------------------------------
-- 2) Remaining orphans from Cycle / membership dates
------------------------------------------------------------
;WITH OrphanClubUsers AS (
    SELECT
        m.UserId,
        m.PurchaseMethod,
        u.PackagePurchaseMethod AS UserPurchaseMethod,
        COALESCE(NULLIF(m.LastPackageId, 0), NULLIF(m.FirstPackageId, 0)) AS MembPackageId,
        COALESCE(m.FirstActivationDate, m.LastActivationDate, m.ActivatedAt, m.Created) AS MembPurchasedAt
    FROM CMS.ClubMemberships m
    INNER JOIN CMS.Users u ON u.Id = m.UserId AND u.IsDeleted = 0
    WHERE m.IsDeleted = 0
      AND NOT EXISTS (
          SELECT 1
          FROM CMS.UserPackagePurchases upp
          LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
          WHERE upp.UserId = m.UserId
            AND upp.IsDeleted = 0
            AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
      )
),
BestCycle AS (
    SELECT
        c.UserId,
        c.PackageId,
        c.PackageAmount,
        c.PurchaseMethod,
        c.PackagePurchasedAt,
        ROW_NUMBER() OVER (PARTITION BY c.UserId ORDER BY c.CycleNumber ASC, c.Id ASC) AS rn
    FROM CMS.ClubMembershipCycles c
    WHERE c.IsDeleted = 0
),
BasePkg AS (
    SELECT TOP (1) Id AS PackageId, Price
    FROM CMS.Packages
    WHERE IsDeleted = 0 AND IsBasePackage = 1
    ORDER BY Id
),
ToInsert AS (
    SELECT
        o.UserId,
        COALESCE(NULLIF(bc.PackageId, 0), o.MembPackageId, b.PackageId) AS PackageId,
        CASE
            WHEN bc.PurchaseMethod IS NOT NULL AND bc.PurchaseMethod <> 0 THEN bc.PurchaseMethod
            WHEN o.PurchaseMethod IS NOT NULL AND o.PurchaseMethod <> 0 THEN o.PurchaseMethod
            WHEN o.UserPurchaseMethod IS NOT NULL AND o.UserPurchaseMethod <> 0 THEN o.UserPurchaseMethod
            ELSE 3 -- Manual (last resort)
        END AS PurchaseMethod,
        COALESCE(bc.PackagePurchasedAt, o.MembPurchasedAt, SYSUTCDATETIME()) AS PurchasedAt,
        CASE
            WHEN bc.PackageAmount IS NOT NULL AND bc.PackageAmount > 0 THEN bc.PackageAmount
            ELSE COALESCE(p.Price, b.Price, 0)
        END AS Amount
    FROM OrphanClubUsers o
    LEFT JOIN BestCycle bc ON bc.UserId = o.UserId AND bc.rn = 1
    CROSS JOIN BasePkg b
    LEFT JOIN CMS.Packages p ON p.Id = COALESCE(NULLIF(bc.PackageId, 0), o.MembPackageId, b.PackageId) AND p.IsDeleted = 0
)
SELECT *
INTO #BackfillCandidates
FROM ToInsert
WHERE PackageId IS NOT NULL AND Amount > 0;

DECLARE @Remaining INT = (SELECT COUNT(*) FROM #BackfillCandidates);
PRINT CONCAT('Remaining orphans to synthetic backfill: ', @Remaining);

DECLARE @UserId BIGINT, @PackageId BIGINT, @PurchaseMethod INT, @PurchasedAt DATETIME2, @Amount BIGINT;
DECLARE @TxId BIGINT;

DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
    SELECT UserId, PackageId, PurchaseMethod, PurchasedAt, Amount
    FROM #BackfillCandidates;

OPEN cur;
FETCH NEXT FROM cur INTO @UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount;

DECLARE @Synthetic INT = 0;

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO CMS.Transactions
    (
        Amount, Description, PaymentStatus, PaymentDate, RefId, Type,
        Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
    )
    VALUES
    (
        @Amount,
        CONCAT(N'بک‌فیل عضویت باشگاه — UserId ', @UserId),
        0, -- Success
        @PurchasedAt,
        CONCAT('UPP-BACKFILL-', @UserId, '-', @PackageId),
        2, -- DepositExternal1
        SYSUTCDATETIME(), NULL, SYSUTCDATETIME(), NULL, 0
    );

    SET @TxId = SCOPE_IDENTITY();

    INSERT INTO CMS.UserPackagePurchases
    (
        UserId, PackageId, PurchaseMethod, PurchasedAt, Amount,
        OrderId, TransactionId, Created, CreatedBy, LastModified, LastModifiedBy, IsDeleted
    )
    VALUES
    (
        @UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount,
        NULL, @TxId, SYSUTCDATETIME(), NULL, SYSUTCDATETIME(), NULL, 0
    );

    SET @Synthetic += 1;
    FETCH NEXT FROM cur INTO @UserId, @PackageId, @PurchaseMethod, @PurchasedAt, @Amount;
END

CLOSE cur;
DEALLOCATE cur;

PRINT CONCAT('Inserted synthetic UPP rows: ', @Synthetic);

DROP TABLE #BackfillCandidates;

------------------------------------------------------------
-- Verify invariant
------------------------------------------------------------
DECLARE @ClubCount INT =
(
    SELECT COUNT(*) FROM CMS.ClubMemberships WHERE IsDeleted = 0
);

DECLARE @OrphansLeft INT =
(
    SELECT COUNT(*)
    FROM CMS.ClubMemberships m
    WHERE m.IsDeleted = 0
      AND NOT EXISTS (
          SELECT 1
          FROM CMS.UserPackagePurchases upp
          LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
          WHERE upp.UserId = m.UserId
            AND upp.IsDeleted = 0
            AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
      )
);

DECLARE @SuccessfulBuyers INT =
(
    SELECT COUNT(DISTINCT upp.UserId)
    FROM CMS.UserPackagePurchases upp
    LEFT JOIN CMS.Transactions t ON t.Id = upp.TransactionId AND t.IsDeleted = 0
    WHERE upp.IsDeleted = 0
      AND (upp.TransactionId IS NULL OR t.PaymentStatus = 0)
);

PRINT CONCAT('ClubMemberships: ', @ClubCount);
PRINT CONCAT('Distinct successful UPP users: ', @SuccessfulBuyers);
PRINT CONCAT('Orphans left (must be 0): ', @OrphansLeft);

IF @OrphansLeft > 0
BEGIN
    ROLLBACK;
    THROW 50001, 'Backfill incomplete — orphans remain; transaction rolled back.', 1;
END

COMMIT;
PRINT 'Backfill committed successfully.';
