-- =============================================================================
-- Company Data Purge Script
-- Removes financial, job, and quote data dated before a cutoff date.
-- Customers and Vendors are always preserved.
--
-- WHAT THIS DELETES (using each entity's own business date, not CreatedAt):
--   • Journal entries (EntryDate) & bank reconciliations (StatementDate)
--   • Bills (BillDate), bill payments (PaymentDate), purchase orders (OrderDate)
--   • Vendor credits (CreditDate), expenses (Date)
--   • Invoices (InvoiceDate), payments (PaymentDate), deposits (ReceivedDate)
--   • Credit memos, refunds, gift cert redemptions tied to deleted invoices
--   • Jobs (IntakeDate, falling back to CreatedAt when null) and all child records
--   • Quotes (QuoteDate) and all child records
--
-- WHAT THIS KEEPS (always):
--   • Customers, customer notes, customer contacts, preferred powders
--   • Vendors
--   • Inventory items and inventory transactions
--   • Equipment, catalog items, pricing tiers
--   • Company settings and configuration
--   • Any record whose business date >= @CutoffDate
--
-- INSTRUCTIONS:
--   1. Set @CompanyId  — find it with: SELECT Id, Name FROM Companies
--   2. Set @CutoffDate — records dated BEFORE this date are deleted
--   3. Run with @DryRun = 1 first and review the row counts printed
--   4. Back up the database before setting @DryRun = 0
--   5. Set @DryRun = 0 and run again to apply
-- =============================================================================

DECLARE @CutoffDate  DATE = '2026-01-01';   -- Delete records dated BEFORE this date
DECLARE @CompanyId   INT  = 0;              -- !! Set to your company ID before running
DECLARE @DryRun      BIT  = 1;              -- 1 = preview counts only  |  0 = apply deletes

-- =============================================================================
SET NOCOUNT ON;

IF @CompanyId = 0
BEGIN
    RAISERROR('ERROR: Set @CompanyId before running this script. Run: SELECT Id, Name FROM Companies', 16, 1);
    RETURN;
END

PRINT '============================================================';
PRINT 'Purge run at: ' + CONVERT(NVARCHAR, GETDATE(), 120);
PRINT 'Company ID  : ' + CAST(@CompanyId  AS NVARCHAR);
PRINT 'Cutoff date : ' + CAST(@CutoffDate AS NVARCHAR) + ' (records BEFORE this date)';
PRINT 'Dry run     : ' + CASE @DryRun WHEN 1 THEN 'YES — no changes will be made' ELSE 'NO — deletes will be applied' END;
PRINT '============================================================';

BEGIN TRANSACTION;

-- ===========================================================================
-- SECTION 1 — JOURNAL ENTRIES & GL
-- Uses EntryDate (JournalEntries) and StatementDate (BankReconciliations)
-- ===========================================================================
PRINT '';
PRINT '--- Section 1: Journal Entries & GL ---';

-- Null the self-referential ReversalOfId FK before deleting
UPDATE JournalEntries
SET    ReversalOfId = NULL
WHERE  CompanyId = @CompanyId
  AND  ReversalOfId IN (SELECT Id FROM JournalEntries WHERE CompanyId = @CompanyId AND CAST(EntryDate AS DATE) < @CutoffDate);

DELETE FROM JournalEntryLines
WHERE  JournalEntryId IN (
    SELECT Id FROM JournalEntries WHERE CompanyId = @CompanyId AND CAST(EntryDate AS DATE) < @CutoffDate);
PRINT 'JournalEntryLines deleted : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JournalEntries
WHERE  CompanyId = @CompanyId AND CAST(EntryDate AS DATE) < @CutoffDate;
PRINT 'JournalEntries deleted    : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM BankReconciliations
WHERE  CompanyId = @CompanyId AND CAST(StatementDate AS DATE) < @CutoffDate;
PRINT 'BankReconciliations deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ===========================================================================
-- SECTION 2 — BILLS, PURCHASE ORDERS & EXPENSES
-- Uses CreditDate (VendorCredits), BillDate (Bills), OrderDate (POs), Date (Expenses)
-- ===========================================================================
PRINT '';
PRINT '--- Section 2: Bills, Purchase Orders & Expenses ---';

-- Vendor credits (must come before Bills because VendorCreditApplications references both)
DELETE FROM VendorCreditApplications
WHERE  VendorCreditId IN (
    SELECT Id FROM VendorCredits WHERE CompanyId = @CompanyId AND CAST(CreditDate AS DATE) < @CutoffDate);
PRINT 'VendorCreditApplications deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM VendorCreditLineItems
WHERE  VendorCreditId IN (
    SELECT Id FROM VendorCredits WHERE CompanyId = @CompanyId AND CAST(CreditDate AS DATE) < @CutoffDate);
PRINT 'VendorCreditLineItems deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM VendorCredits
WHERE  CompanyId = @CompanyId AND CAST(CreditDate AS DATE) < @CutoffDate;
PRINT 'VendorCredits deleted     : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Bills
DELETE FROM BillPayments
WHERE  BillId IN (
    SELECT Id FROM Bills WHERE CompanyId = @CompanyId AND CAST(BillDate AS DATE) < @CutoffDate);
PRINT 'BillPayments deleted      : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM BillLineItems
WHERE  BillId IN (
    SELECT Id FROM Bills WHERE CompanyId = @CompanyId AND CAST(BillDate AS DATE) < @CutoffDate);
PRINT 'BillLineItems deleted     : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM Bills
WHERE  CompanyId = @CompanyId AND CAST(BillDate AS DATE) < @CutoffDate;
PRINT 'Bills deleted             : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Purchase orders
DELETE FROM PurchaseOrderItems
WHERE  PurchaseOrderId IN (
    SELECT Id FROM PurchaseOrders WHERE CompanyId = @CompanyId AND CAST(OrderDate AS DATE) < @CutoffDate);
PRINT 'PurchaseOrderItems deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM PurchaseOrders
WHERE  CompanyId = @CompanyId AND CAST(OrderDate AS DATE) < @CutoffDate;
PRINT 'PurchaseOrders deleted    : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Expenses (Date column)
DELETE FROM Expenses
WHERE  CompanyId = @CompanyId AND CAST([Date] AS DATE) < @CutoffDate;
PRINT 'Expenses deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ===========================================================================
-- SECTION 3 — INVOICES, PAYMENTS & DEPOSITS
-- Uses InvoiceDate (Invoices), PaymentDate (Payments), ReceivedDate (Deposits)
-- CreditMemos/Refunds/GiftCertRedemptions have no standalone date — deleted
-- only when their parent invoice falls within the cutoff.
-- ===========================================================================
PRINT '';
PRINT '--- Section 3: Invoices, Payments & Deposits ---';

-- CreditMemos: NULL the OriginalInvoiceId FK before deleting the invoice it points to
UPDATE CreditMemos
SET    OriginalInvoiceId = NULL
WHERE  CompanyId = @CompanyId
  AND  OriginalInvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);

DELETE FROM CreditMemoApplications
WHERE  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate)
  OR   CreditMemoId IN (
    SELECT Id FROM CreditMemos WHERE CompanyId = @CompanyId AND CAST(CreatedAt AS DATE) < @CutoffDate);
PRINT 'CreditMemoApplications deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM CreditMemos
WHERE  CompanyId = @CompanyId AND CAST(CreatedAt AS DATE) < @CutoffDate;
PRINT 'CreditMemos deleted       : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Refunds and gift-cert redemptions tied to deleted invoices
DELETE FROM Refunds
WHERE  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);
PRINT 'Refunds deleted           : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM GiftCertificateRedemptions
WHERE  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);
PRINT 'GiftCertificateRedemptions deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Payments (PaymentDate)
DELETE FROM Payments
WHERE  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);
PRINT 'Payments deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- InvoiceItems (NULL SourceJobItemId on any invoice items that survive but point at deleted jobs)
UPDATE InvoiceItems
SET    SourceJobItemId = NULL
WHERE  SourceJobItemId IN (
    SELECT ji.Id FROM JobItems ji
    INNER JOIN Jobs j ON ji.JobId = j.Id
    WHERE  j.CompanyId = @CompanyId
      AND  CAST(COALESCE(j.IntakeDate, j.CreatedAt) AS DATE) < @CutoffDate);

DELETE FROM InvoiceItems
WHERE  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);
PRINT 'InvoiceItems deleted      : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Deposits: clear the AppliedToInvoiceId FK before deleting the invoices
UPDATE Deposits
SET    AppliedToInvoiceId = NULL,
       AppliedDate        = NULL
WHERE  CompanyId = @CompanyId
  AND  AppliedToInvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);

-- Now delete deposits that fall within the cutoff (ReceivedDate)
DELETE FROM Deposits
WHERE  CompanyId = @CompanyId AND CAST(ReceivedDate AS DATE) < @CutoffDate;
PRINT 'Deposits deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Notification logs referencing deleted invoices
UPDATE NotificationLogs
SET    InvoiceId = NULL
WHERE  CompanyId = @CompanyId
  AND  InvoiceId IN (
    SELECT Id FROM Invoices WHERE CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate);

DELETE FROM Invoices
WHERE  CompanyId = @CompanyId AND CAST(InvoiceDate AS DATE) < @CutoffDate;
PRINT 'Invoices deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ===========================================================================
-- SECTION 4 — JOBS
-- Uses COALESCE(IntakeDate, CreatedAt) — IntakeDate is the business date;
-- falls back to CreatedAt when not set (e.g. jobs created before IntakeDate existed).
-- ===========================================================================
PRINT '';
PRINT '--- Section 4: Jobs ---';

-- NULL FKs in other tables that point to jobs/job-items being deleted --

-- BillLineItems.JobId (bill survived but referenced a deleted job)
UPDATE BillLineItems
SET    JobId = NULL
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);

-- Expenses.JobId
UPDATE Expenses
SET    JobId = NULL
WHERE  CompanyId = @CompanyId
  AND  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);

-- Appointments.JobId
UPDATE Appointments
SET    JobId = NULL
WHERE  CompanyId = @CompanyId
  AND  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);

-- Deposits.JobId (NoAction FK — must NULL before deleting job)
UPDATE Deposits
SET    JobId = NULL
WHERE  CompanyId = @CompanyId
  AND  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);

-- NotificationLogs.JobId
UPDATE NotificationLogs
SET    JobId = NULL
WHERE  CompanyId = @CompanyId
  AND  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);

-- OvenBatchItems: delete before OvenBatches and before JobItems
DELETE FROM OvenBatchItems
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'OvenBatchItems deleted    : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Clean up now-empty OvenBatches (batches belonging to this company with no remaining items)
DELETE FROM OvenBatches
WHERE  CompanyId = @CompanyId
  AND  Id NOT IN (SELECT DISTINCT OvenBatchId FROM OvenBatchItems);
PRINT 'OvenBatches deleted       : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ReworkRecords (JobId required FK; ReworkJobId optional)
DELETE FROM ReworkRecords
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate)
  OR  ReworkJobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'ReworkRecords deleted     : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- JobItem children (coats and prep services)
DELETE FROM JobItemCoats
WHERE  JobItemId IN (
    SELECT Id FROM JobItems WHERE JobId IN (
        SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
          AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate));
PRINT 'JobItemCoats deleted      : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobItemPrepServices
WHERE  JobItemId IN (
    SELECT Id FROM JobItems WHERE JobId IN (
        SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
          AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate));
PRINT 'JobItemPrepServices deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobItems
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobItems deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- Job metadata tables
DELETE FROM JobChangeHistories
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobChangeHistories deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobTimeEntries
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobTimeEntries deleted    : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobPhotos
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobPhotos deleted         : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobNotes
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobNotes deleted          : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobStatusHistory
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobStatusHistory deleted  : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM JobDailyPriorities
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'JobDailyPriorities deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM PowderUsageLogs
WHERE  JobId IN (
    SELECT Id FROM Jobs WHERE CompanyId = @CompanyId
      AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate);
PRINT 'PowderUsageLogs deleted   : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM AiItemPredictions
WHERE  CompanyId = @CompanyId AND CAST(CreatedAt AS DATE) < @CutoffDate;
PRINT 'AiItemPredictions deleted : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM Jobs
WHERE  CompanyId = @CompanyId
  AND  CAST(COALESCE(IntakeDate, CreatedAt) AS DATE) < @CutoffDate;
PRINT 'Jobs deleted              : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ===========================================================================
-- SECTION 5 — QUOTES
-- Uses QuoteDate
-- ===========================================================================
PRINT '';
PRINT '--- Section 5: Quotes ---';

-- NULL FKs that point to quotes being deleted
UPDATE Deposits
SET    QuoteId = NULL
WHERE  CompanyId = @CompanyId
  AND  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);

UPDATE NotificationLogs
SET    QuoteId = NULL
WHERE  CompanyId = @CompanyId
  AND  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);

-- QuoteItem children
DELETE FROM QuoteItemCoats
WHERE  QuoteItemId IN (
    SELECT Id FROM QuoteItems WHERE QuoteId IN (
        SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate));
PRINT 'QuoteItemCoats deleted    : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM QuoteItemPrepServices
WHERE  QuoteItemId IN (
    SELECT Id FROM QuoteItems WHERE QuoteId IN (
        SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate));
PRINT 'QuoteItemPrepServices deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM QuoteItems
WHERE  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);
PRINT 'QuoteItems deleted        : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM QuoteChangeHistories
WHERE  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);
PRINT 'QuoteChangeHistories deleted: ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM QuotePhotos
WHERE  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);
PRINT 'QuotePhotos deleted       : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM QuotePrepServices
WHERE  QuoteId IN (
    SELECT Id FROM Quotes WHERE CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate);
PRINT 'QuotePrepServices deleted : ' + CAST(@@ROWCOUNT AS NVARCHAR);

DELETE FROM Quotes
WHERE  CompanyId = @CompanyId AND CAST(QuoteDate AS DATE) < @CutoffDate;
PRINT 'Quotes deleted            : ' + CAST(@@ROWCOUNT AS NVARCHAR);

-- ===========================================================================
-- SUMMARY & COMMIT / ROLLBACK
-- ===========================================================================
PRINT '';
PRINT '============================================================';

IF @DryRun = 1
BEGIN
    PRINT 'DRY RUN complete — rolling back. No data was changed.';
    PRINT 'Set @DryRun = 0 and run again to apply the deletes.';
    ROLLBACK TRANSACTION;
END
ELSE
BEGIN
    PRINT 'Purge complete — committing.';
    COMMIT TRANSACTION;
END
