using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using PowderCoating.Core.Entities;
using PowderCoating.Core.Interfaces;
using PowderCoating.Core.Interfaces.Repositories;
using PowderCoating.Infrastructure.Data;

namespace PowderCoating.Infrastructure.Repositories;

/// <summary>
/// Concrete implementation of <see cref="IUnitOfWork"/> that coordinates all entity repositories
/// and exposes transaction management for the application layer.
/// <para>
/// All entity repositories are lazily instantiated — a <see cref="Repository{T}"/> is only
/// allocated the first time the corresponding property is accessed.  This keeps the per-request
/// memory footprint small when only a handful of entities are needed.
/// </para>
/// <para>
/// <b>Persistence</b>: call <see cref="SaveChangesAsync"/> or <see cref="CompleteAsync"/>
/// (identical behaviour) to flush pending changes to the database.
/// </para>
/// <para>
/// <b>Explicit transactions</b>: use <see cref="BeginTransactionAsync"/> /
/// <see cref="CommitTransactionAsync"/> / <see cref="RollbackTransactionAsync"/> when multiple
/// SaveChanges calls must succeed or fail atomically.  For a simpler fire-and-forget pattern,
/// prefer <see cref="ExecuteInTransactionAsync(Func{Task})"/> which wraps the operation in an
/// EF Core execution-strategy-aware transaction automatically.
/// </para>
/// </summary>
public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _context;
    private IDbContextTransaction? _transaction;

    // Multi-tenancy
    private IRepository<Company>? _companies;
    private IRepository<CompanyOperatingCosts>? _companyOperatingCosts;
    private IRepository<CompanyPreferences>? _companyPreferences;
    private IRepository<CompanySmsAgreement>? _companySmsAgreements;

    // AI Predictions
    private IRepository<AiItemPrediction>? _aiItemPredictions;

    // Powder Insights
    private IPowderUsageLogRepository? _powderUsageLogs;

    // Core repositories
    private ICustomerRepository? _customers;
    private IJobRepository? _jobs;
    private IRepository<JobDailyPriority>? _jobDailyPriorities;
    private IRepository<JobItem>? _jobItems;
    private IJobItemCoatRepository? _jobItemCoats;
    private IRepository<JobItemPrepService>? _jobItemPrepServices;
    private IRepository<JobChangeHistory>? _jobChangeHistories;
    private IRepository<JobPrepService>? _jobPrepServices;
    private IQuoteRepository? _quotes;
    private IRepository<QuotePhoto>? _quotePhotos;
    private IRepository<QuoteItem>? _quoteItems;
    private IRepository<QuoteItemCoat>? _quoteItemCoats;
    private IRepository<QuoteItemPrepService>? _quoteItemPrepServices;
    private IRepository<QuoteChangeHistory>? _quoteChangeHistories;
    private IRepository<InventoryItem>? _inventoryItems;
    private IPlainRepository<PowderCatalogItem>? _powderCatalog;
    private IInventoryTransactionRepository? _inventoryTransactions;
    private IRepository<Equipment>? _equipment;
    private IRepository<OvenCost>? _ovenCosts;
    private IRepository<CompanyBlastSetup>? _blastSetups;
    private IRepository<MaintenanceRecord>? _maintenanceRecords;
    private IRepository<Vendor>? _vendors;
    private IJobPhotoRepository? _jobPhotos;
    private IRepository<JobNote>? _jobNotes;
    private IRepository<CustomerNote>? _customerNotes;
    private IRepository<CustomerContact>? _customerContacts;
    private IRepository<CustomerPreferredPowder>? _customerPreferredPowders;
    private IRepository<JobStatusHistory>? _jobStatusHistory;
    private IRepository<PricingTier>? _pricingTiers;

    // Lookup tables (replacing enums)
    private IRepository<JobStatusLookup>? _jobStatusLookups;
    private IRepository<JobPriorityLookup>? _jobPriorityLookups;
    private IRepository<QuoteStatusLookup>? _quoteStatusLookups;
    private IRepository<InventoryCategoryLookup>? _inventoryCategoryLookups;
    private IRepository<AppointmentStatusLookup>? _appointmentStatusLookups;
    private IRepository<AppointmentTypeLookup>? _appointmentTypeLookups;
    private IRepository<PrepService>? _prepServices;

    // Appointments
    private IRepository<Appointment>? _appointments;

    // Product Catalog
    private IRepository<CatalogCategory>? _catalogCategories;
    private IRepository<CatalogItem>? _catalogItems;
    private IRepository<CatalogPriceCheckReport>? _catalogPriceCheckReports;

    // Notifications
    private INotificationLogRepository? _notificationLogs;
    private IRepository<NotificationTemplate>? _notificationTemplates;

    // Subscription
    private IRepository<SubscriptionPlanConfig>? _subscriptionPlanConfigs;

    // Job Templates
    private IJobTemplateRepository? _jobTemplates;
    private IRepository<JobTemplateItem>? _jobTemplateItems;
    private IRepository<JobTemplateItemCoat>? _jobTemplateItemCoats;
    private IRepository<JobTemplateItemPrepService>? _jobTemplateItemPrepServices;

    // Platform content
    private IPlainRepository<Announcement>? _announcements;
    private IPlainRepository<BannedIp>? _bannedIps;
    private IPlainRepository<DashboardTip>? _dashboardTips;
    private IInAppNotificationRepository? _inAppNotifications;
    private IPlainRepository<ReleaseNote>? _releaseNotes;

    // Bug Reports
    private IRepository<BugReport>? _bugReports;
    private IRepository<BugReportAttachment>? _bugReportAttachments;
    private IRepository<ContactSubmission>? _contactSubmissions;
    private IRepository<ManufacturerLookupPattern>? _manufacturerLookupPatterns;

    // Gift Certificates
    private IRepository<GiftCertificate>? _giftCertificates;
    private IRepository<GiftCertificateRedemption>? _giftCertificateRedemptions;

    // Customer Intake Kiosk
    private IRepository<KioskSession>? _kioskSessions;

    // Employee Timeclock
    private IRepository<EmployeeClockEntry>? _employeeClockEntries;
    private IRepository<TimeclockKioskDevice>? _timeclockKioskDevices;

    // Custom Formula Templates
    private IRepository<CustomItemTemplate>? _customItemTemplates;

    // Formula Community Library
    private IPlainRepository<FormulaLibraryItem>? _formulaLibrary;
    private IRepository<FormulaLibraryImport>? _formulaLibraryImports;
    private IPlainRepository<FormulaLibraryRating>? _formulaLibraryRatings;

    // Purchase Orders
    private IPurchaseOrderRepository? _purchaseOrders;
    private IRepository<PurchaseOrderItem>? _purchaseOrderItems;

    // Oven Scheduling
    private IRepository<OvenBatch>? _ovenBatches;
    private IRepository<OvenBatchItem>? _ovenBatchItems;

    // Invoices, Payments & Deposits
    private IInvoiceRepository? _invoices;
    private IRepository<InvoiceItem>? _invoiceItems;
    private IRepository<Payment>? _payments;
    private IRepository<Deposit>? _deposits;

    // Expense Tracking / Accounts Payable
    private IRepository<Account>? _accounts;
    private IBillRepository? _bills;
    private IRepository<BillLineItem>? _billLineItems;
    private IRepository<BillPayment>? _billPayments;
    private IRepository<Expense>? _expenses;

    // Manual Journal Entries
    private IRepository<JournalEntry>? _journalEntries;
    private IRepository<JournalEntryLine>? _journalEntryLines;

    // Vendor Credits
    private IRepository<VendorCredit>? _vendorCredits;
    private IRepository<VendorCreditLineItem>? _vendorCreditLineItems;
    private IRepository<VendorCreditApplication>? _vendorCreditApplications;

    // Bank Reconciliation
    private IRepository<BankReconciliation>? _bankReconciliations;

    // Tax Rates
    private IRepository<TaxRate>? _taxRates;

    // Recurring Transactions
    private IRepository<RecurringTemplate>? _recurringTemplates;
    private IRepository<FixedAsset>? _fixedAssets;
    private IRepository<FixedAssetDepreciationEntry>? _fixedAssetDepreciationEntries;
    private IRepository<Budget>? _budgets;
    private IRepository<BudgetLine>? _budgetLines;
    private IRepository<YearEndClose>? _yearEndCloses;

    /// <summary>
    /// Initialises the unit of work with the scoped <paramref name="context"/>.
    /// The context is shared across all repositories created by this instance so that
    /// all reads and writes within a single request participate in the same EF Core identity map
    /// and change-tracker, enabling zero-copy entity sharing between repositories.
    /// </summary>
    public UnitOfWork(ApplicationDbContext context)
    {
        _context = context;
    }

    // -------------------------------------------------------------------------
    // Repository properties — lazy-initialised via the null-coalescing assignment
    // operator (??=).  Each property creates one Repository<T> instance at most
    // per UnitOfWork lifetime (= per HTTP request when registered as Scoped).
    // Repositories share the underlying DbContext so they share the change tracker.
    // -------------------------------------------------------------------------

    /// <summary>Repository for <see cref="Company"/> tenant records. Soft-delete filter only (no tenant filter — SuperAdmin manages all companies).</summary>
    public IRepository<Company> Companies =>
        _companies ??= new Repository<Company>(_context);

    /// <summary>Repository for <see cref="CompanyOperatingCosts"/> (one-to-one with Company).</summary>
    public IRepository<CompanyOperatingCosts> CompanyOperatingCosts =>
        _companyOperatingCosts ??= new Repository<CompanyOperatingCosts>(_context);

    /// <summary>Repository for <see cref="CompanyPreferences"/> (one-to-one with Company).</summary>
    public IRepository<CompanyPreferences> CompanyPreferences =>
        _companyPreferences ??= new Repository<CompanyPreferences>(_context);

    /// <summary>Repository for <see cref="CompanySmsAgreement"/> audit records. Tenant-filtered; never soft-deleted — legal audit trail.</summary>
    public IRepository<CompanySmsAgreement> CompanySmsAgreements =>
        _companySmsAgreements ??= new Repository<CompanySmsAgreement>(_context);

    // AI Predictions
    /// <summary>Repository for <see cref="AiItemPrediction"/> records; tenant-filtered. Shared between QuoteItem and JobItem via a single nullable FK — no duplication on quote→job conversion.</summary>
    public IRepository<AiItemPrediction> AiItemPredictions =>
        _aiItemPredictions ??= new Repository<AiItemPrediction>(_context);

    // Powder Insights
    /// <summary>Repository for <see cref="PowderUsageLog"/> records capturing per-coat powder consumption; used by powder-usage analytics.</summary>
    public IPowderUsageLogRepository PowderUsageLogs =>
        _powderUsageLogs ??= new PowderUsageLogRepository(_context);

    // Core repositories
    /// <summary>Repository for <see cref="Customer"/> records (commercial and non-commercial); tenant-filtered with soft delete.</summary>
    public ICustomerRepository Customers =>
        _customers ??= new CustomerRepository(_context);

    /// <summary>Repository for <see cref="Job"/> records progressing through the 16-status lifecycle; tenant-filtered with soft delete.</summary>
    public IJobRepository Jobs =>
        _jobs ??= new JobRepository(_context);

    /// <summary>Repository for <see cref="JobDailyPriority"/> overrides that let supervisors re-order the shop floor queue.</summary>
    public IRepository<JobDailyPriority> JobDailyPriorities =>
        _jobDailyPriorities ??= new Repository<JobDailyPriority>(_context);

    /// <summary>Repository for <see cref="JobItem"/> line-items; tenant-filtered with soft delete.</summary>
    public IRepository<JobItem> JobItems =>
        _jobItems ??= new Repository<JobItem>(_context);

    /// <summary>Repository for <see cref="JobItemCoat"/> powder coat passes; tenant-filtered with soft delete.</summary>
    public IJobItemCoatRepository JobItemCoats =>
        _jobItemCoats ??= new JobItemCoatRepository(_context);
    public IRepository<JobItemPrepService> JobItemPrepServices =>
        _jobItemPrepServices ??= new Repository<JobItemPrepService>(_context);

    /// <summary>Repository for <see cref="JobChangeHistory"/> audit entries; tenant-filtered with soft delete.</summary>
    public IRepository<JobChangeHistory> JobChangeHistories =>
        _jobChangeHistories ??= new Repository<JobChangeHistory>(_context);

    /// <summary>Repository for <see cref="JobPrepService"/> job-level prep service assignments; tenant-filtered with soft delete.</summary>
    public IRepository<JobPrepService> JobPrepServices =>
        _jobPrepServices ??= new Repository<JobPrepService>(_context);

    /// <summary>Repository for <see cref="Quote"/> records with multi-item pricing; tenant-filtered with soft delete.</summary>
    public IQuoteRepository Quotes =>
        _quotes ??= new QuoteRepository(_context);

    /// <summary>Repository for <see cref="QuotePhoto"/> AI photo uploads; tenant-filtered with soft delete.</summary>
    public IRepository<QuotePhoto> QuotePhotos =>
        _quotePhotos ??= new Repository<QuotePhoto>(_context);

    /// <summary>Repository for <see cref="QuoteItem"/> line-items; tenant-filtered with soft delete.</summary>
    public IRepository<QuoteItem> QuoteItems =>
        _quoteItems ??= new Repository<QuoteItem>(_context);

    /// <summary>Repository for <see cref="QuoteItemCoat"/> powder coat passes on a quote item; tenant-filtered with soft delete.</summary>
    public IRepository<QuoteItemCoat> QuoteItemCoats =>
        _quoteItemCoats ??= new Repository<QuoteItemCoat>(_context);

    /// <summary>Repository for <see cref="QuoteItemPrepService"/> prep-service assignments on a quote item; tenant-filtered with soft delete.</summary>
    public IRepository<QuoteItemPrepService> QuoteItemPrepServices =>
        _quoteItemPrepServices ??= new Repository<QuoteItemPrepService>(_context);

    /// <summary>Repository for <see cref="QuoteChangeHistory"/> audit entries; tenant-filtered with soft delete.</summary>
    public IRepository<QuoteChangeHistory> QuoteChangeHistories =>
        _quoteChangeHistories ??= new Repository<QuoteChangeHistory>(_context);

    /// <summary>Repository for <see cref="InventoryItem"/> powder and material stock; tenant-filtered with soft delete.</summary>
    public IRepository<InventoryItem> InventoryItems =>
        _inventoryItems ??= new Repository<InventoryItem>(_context);

    /// <summary>Platform-level powder catalog — no tenant filter, no soft delete.</summary>
    public IPlainRepository<PowderCatalogItem> PowderCatalog =>
        _powderCatalog ??= new PlainRepository<PowderCatalogItem>(_context);

    /// <summary>Repository for <see cref="InventoryTransaction"/> stock movements; tenant-filtered with soft delete.</summary>
    public IInventoryTransactionRepository InventoryTransactions =>
        _inventoryTransactions ??= new InventoryTransactionRepository(_context);

    /// <summary>Repository for <see cref="Equipment"/> records (ovens, sandblasters, booths); tenant-filtered with soft delete.</summary>
    public IRepository<Equipment> Equipment =>
        _equipment ??= new Repository<Equipment>(_context);

    /// <summary>Repository for <see cref="OvenCost"/> named oven configurations used by the Oven Scheduler; tenant-filtered with soft delete.</summary>
    public IRepository<OvenCost> OvenCosts =>
        _ovenCosts ??= new Repository<OvenCost>(_context);

    /// <summary>Repository for <see cref="CompanyBlastSetup"/> named blast setups; tenant-filtered with soft delete.</summary>
    public IRepository<CompanyBlastSetup> BlastSetups =>
        _blastSetups ??= new Repository<CompanyBlastSetup>(_context);

    /// <summary>Repository for <see cref="MaintenanceRecord"/> equipment maintenance records; tenant-filtered with soft delete.</summary>
    public IRepository<MaintenanceRecord> MaintenanceRecords =>
        _maintenanceRecords ??= new Repository<MaintenanceRecord>(_context);

    /// <summary>Repository for <see cref="Vendor"/> supplier records; tenant-filtered with soft delete.</summary>
    public IRepository<Vendor> Vendors =>
        _vendors ??= new Repository<Vendor>(_context);

    /// <summary>Repository for <see cref="JobPhoto"/> attachments; tenant-filtered with soft delete.</summary>
    public IJobPhotoRepository JobPhotos =>
        _jobPhotos ??= new JobPhotoRepository(_context);

    /// <summary>Repository for <see cref="JobNote"/> free-text staff notes on jobs; tenant-filtered with soft delete.</summary>
    public IRepository<JobNote> JobNotes =>
        _jobNotes ??= new Repository<JobNote>(_context);

    /// <summary>Repository for <see cref="CustomerNote"/> free-text staff notes on customer records; tenant-filtered with soft delete.</summary>
    public IRepository<CustomerNote> CustomerNotes =>
        _customerNotes ??= new Repository<CustomerNote>(_context);
    /// <summary>Repository for <see cref="CustomerContact"/> additional contacts (billing, ops, drop-off) on commercial accounts; tenant-filtered with soft delete.</summary>
    public IRepository<CustomerContact> CustomerContacts =>
        _customerContacts ??= new Repository<CustomerContact>(_context);
    public IRepository<CustomerPreferredPowder> CustomerPreferredPowders =>
        _customerPreferredPowders ??= new Repository<CustomerPreferredPowder>(_context);

    /// <summary>Repository for <see cref="JobStatusHistory"/> status-transition audit records; tenant-filtered with soft delete.</summary>
    public IRepository<JobStatusHistory> JobStatusHistory =>
        _jobStatusHistory ??= new Repository<JobStatusHistory>(_context);

    /// <summary>Repository for <see cref="PricingTier"/> customer discount tiers; tenant-filtered with soft delete.</summary>
    public IRepository<PricingTier> PricingTiers =>
        _pricingTiers ??= new Repository<PricingTier>(_context);

    // Lookup tables (replacing enums)
    // These are stored in the database instead of C# enums so that tenants can
    // customise display names, colours, and display order without a code deployment.
    /// <summary>Repository for <see cref="JobStatusLookup"/> DB-backed job status definitions.</summary>
    public IRepository<JobStatusLookup> JobStatusLookups =>
        _jobStatusLookups ??= new Repository<JobStatusLookup>(_context);

    /// <summary>Repository for <see cref="JobPriorityLookup"/> DB-backed job priority definitions.</summary>
    public IRepository<JobPriorityLookup> JobPriorityLookups =>
        _jobPriorityLookups ??= new Repository<JobPriorityLookup>(_context);

    /// <summary>Repository for <see cref="QuoteStatusLookup"/> DB-backed quote status definitions.</summary>
    public IRepository<QuoteStatusLookup> QuoteStatusLookups =>
        _quoteStatusLookups ??= new Repository<QuoteStatusLookup>(_context);

    /// <summary>Repository for <see cref="InventoryCategoryLookup"/> user-defined inventory categories.</summary>
    public IRepository<InventoryCategoryLookup> InventoryCategoryLookups =>
        _inventoryCategoryLookups ??= new Repository<InventoryCategoryLookup>(_context);

    /// <summary>Repository for <see cref="AppointmentStatusLookup"/> appointment status definitions.</summary>
    public IRepository<AppointmentStatusLookup> AppointmentStatusLookups =>
        _appointmentStatusLookups ??= new Repository<AppointmentStatusLookup>(_context);

    /// <summary>Repository for <see cref="AppointmentTypeLookup"/> appointment type definitions.</summary>
    public IRepository<AppointmentTypeLookup> AppointmentTypeLookups =>
        _appointmentTypeLookups ??= new Repository<AppointmentTypeLookup>(_context);

    /// <summary>Repository for <see cref="PrepService"/> prep-service catalog entries shared across quotes and jobs.</summary>
    public IRepository<PrepService> PrepServices =>
        _prepServices ??= new Repository<PrepService>(_context);

/// <summary>Repository for <see cref="ReworkRecord"/> quality-failure and remediation records; tenant-filtered with soft delete.</summary>
    private IRepository<ReworkRecord>? _reworkRecords;
    public IRepository<ReworkRecord> ReworkRecords =>
        _reworkRecords ??= new Repository<ReworkRecord>(_context);

    /// <summary>Repository for <see cref="Refund"/> customer refund records; tenant-filtered with soft delete.</summary>
    private IRepository<Refund>? _refunds;
    public IRepository<Refund> Refunds =>
        _refunds ??= new Repository<Refund>(_context);

    /// <summary>Repository for <see cref="CreditMemo"/> records issued to customers; unique memo number per company.</summary>
    private IRepository<CreditMemo>? _creditMemos;
    public IRepository<CreditMemo> CreditMemos =>
        _creditMemos ??= new Repository<CreditMemo>(_context);

    /// <summary>Repository for <see cref="CreditMemoApplication"/> records linking credit memos to specific invoices.</summary>
    private IRepository<CreditMemoApplication>? _creditMemoApplications;
    public IRepository<CreditMemoApplication> CreditMemoApplications =>
        _creditMemoApplications ??= new Repository<CreditMemoApplication>(_context);

    /// <summary>Repository for <see cref="JobTimeEntry"/> clock-in/clock-out worker time records; used for labour-cost calculations.</summary>
    private IRepository<JobTimeEntry>? _jobTimeEntries;
    public IRepository<JobTimeEntry> JobTimeEntries =>
        _jobTimeEntries ??= new Repository<JobTimeEntry>(_context);

    // Appointments
    /// <summary>Repository for <see cref="Appointment"/> customer appointment records; tenant-filtered with soft delete.</summary>
    public IRepository<Appointment> Appointments =>
        _appointments ??= new Repository<Appointment>(_context);

    // Product Catalog
    /// <summary>Repository for <see cref="CatalogCategory"/> hierarchical service catalog categories; tenant-filtered with soft delete.</summary>
    public IRepository<CatalogCategory> CatalogCategories =>
        _catalogCategories ??= new Repository<CatalogCategory>(_context);

    /// <summary>Repository for <see cref="CatalogItem"/> pre-priced service catalog items; tenant-filtered with soft delete.</summary>
    public IRepository<CatalogItem> CatalogItems =>
        _catalogItems ??= new Repository<CatalogItem>(_context);

    /// <summary>Repository for <see cref="CatalogPriceCheckReport"/> AI price-check results archived per company.</summary>
    public IRepository<CatalogPriceCheckReport> CatalogPriceCheckReports =>
        _catalogPriceCheckReports ??= new Repository<CatalogPriceCheckReport>(_context);

    // Notifications
    /// <summary>Repository for <see cref="NotificationLog"/> outbound notification audit records; provides IgnoreQueryFilters lookups by InvoiceId, QuoteId, and JobId for notification history panels.</summary>
    public INotificationLogRepository NotificationLogs =>
        _notificationLogs ??= new NotificationLogRepository(_context);

    /// <summary>Repository for <see cref="NotificationTemplate"/> per-company channel template overrides; unique on (CompanyId, Type, Channel).</summary>
    public IRepository<NotificationTemplate> NotificationTemplates =>
        _notificationTemplates ??= new Repository<NotificationTemplate>(_context);

    // Subscription
    /// <summary>Repository for <see cref="SubscriptionPlanConfig"/> Stripe plan definitions; global (no tenant filter).</summary>
    public IRepository<SubscriptionPlanConfig> SubscriptionPlanConfigs =>
        _subscriptionPlanConfigs ??= new Repository<SubscriptionPlanConfig>(_context);

    // Platform content
    /// <summary>Repository for <see cref="Announcement"/> platform-wide announcements; no tenant filter, no soft delete.</summary>
    public IPlainRepository<Announcement> Announcements =>
        _announcements ??= new PlainRepository<Announcement>(_context);

    /// <summary>Repository for <see cref="BannedIp"/> IP ban records; no tenant filter, no soft delete.</summary>
    public IPlainRepository<BannedIp> BannedIps =>
        _bannedIps ??= new PlainRepository<BannedIp>(_context);

    /// <summary>Repository for <see cref="DashboardTip"/> rotating tip-of-the-day entries; no tenant filter, no soft delete.</summary>
    public IPlainRepository<DashboardTip> DashboardTips =>
        _dashboardTips ??= new PlainRepository<DashboardTip>(_context);

    /// <summary>Repository for <see cref="InAppNotification"/> bell-notification records; tenant-filtered with soft delete.</summary>
    public IInAppNotificationRepository InAppNotifications =>
        _inAppNotifications ??= new InAppNotificationRepository(_context);

    /// <summary>Repository for <see cref="ReleaseNote"/> platform changelog entries; no tenant filter, no soft delete.</summary>
    public IPlainRepository<ReleaseNote> ReleaseNotes =>
        _releaseNotes ??= new PlainRepository<ReleaseNote>(_context);

    // Bug Reports
    /// <summary>Repository for <see cref="BugReport"/> user-submitted bug reports; tenant-filtered with soft delete.</summary>
    public IRepository<BugReport> BugReports =>
        _bugReports ??= new Repository<BugReport>(_context);

    public IRepository<BugReportAttachment> BugReportAttachments =>
        _bugReportAttachments ??= new Repository<BugReportAttachment>(_context);

    // Contact Us
    /// <summary>Repository for <see cref="ContactSubmission"/> contact form submissions; platform admins see all, company users see their own.</summary>
    public IRepository<ContactSubmission> ContactSubmissions =>
        _contactSubmissions ??= new Repository<ContactSubmission>(_context);

    /// <summary>Repository for <see cref="ManufacturerLookupPattern"/> global AI URL patterns; soft-delete only (CompanyId = 0 by convention).</summary>
    public IRepository<ManufacturerLookupPattern> ManufacturerLookupPatterns =>
        _manufacturerLookupPatterns ??= new Repository<ManufacturerLookupPattern>(_context);

    // Gift Certificates
    /// <summary>Repository for <see cref="GiftCertificate"/> records; certificate code unique per company.</summary>
    public IRepository<GiftCertificate> GiftCertificates =>
        _giftCertificates ??= new Repository<GiftCertificate>(_context);

    /// <summary>Repository for <see cref="GiftCertificateRedemption"/> usage events against a gift certificate.</summary>
    public IRepository<GiftCertificateRedemption> GiftCertificateRedemptions =>
        _giftCertificateRedemptions ??= new Repository<GiftCertificateRedemption>(_context);

    /// <summary>Repository for <see cref="KioskSession"/> customer self-service intake sessions; tenant-filtered with soft delete.</summary>
    public IRepository<KioskSession> KioskSessions =>
        _kioskSessions ??= new Repository<KioskSession>(_context);

    /// <summary>Repository for <see cref="EmployeeClockEntry"/> facility-level clock-in/clock-out records; tenant-filtered with soft delete. Multiple entries per day are fully supported.</summary>
    public IRepository<EmployeeClockEntry> EmployeeClockEntries =>
        _employeeClockEntries ??= new Repository<EmployeeClockEntry>(_context);

    /// <summary>Repository for <see cref="TimeclockKioskDevice"/> activated tablet records; one row per device. Delete a row to revoke that device's access.</summary>
    public IRepository<TimeclockKioskDevice> TimeclockKioskDevices =>
        _timeclockKioskDevices ??= new Repository<TimeclockKioskDevice>(_context);

    /// <summary>Repository for <see cref="CustomItemTemplate"/> per-company reusable NCalc pricing formula templates; tenant-filtered with soft delete.</summary>
    public IRepository<CustomItemTemplate> CustomItemTemplates =>
        _customItemTemplates ??= new Repository<CustomItemTemplate>(_context);

    /// <summary>Repository for <see cref="FormulaLibraryItem"/> community library entries; platform-level, no tenant filter.</summary>
    public IPlainRepository<FormulaLibraryItem> FormulaLibrary =>
        _formulaLibrary ??= new PlainRepository<FormulaLibraryItem>(_context);

    /// <summary>Repository for <see cref="FormulaLibraryImport"/> per-company import records; tenant-filtered with soft delete.</summary>
    public IRepository<FormulaLibraryImport> FormulaLibraryImports =>
        _formulaLibraryImports ??= new Repository<FormulaLibraryImport>(_context);

    /// <summary>Repository for <see cref="FormulaLibraryRating"/> per-company thumbs votes; platform-level, no tenant filter.</summary>
    public IPlainRepository<FormulaLibraryRating> FormulaLibraryRatings =>
        _formulaLibraryRatings ??= new PlainRepository<FormulaLibraryRating>(_context);

    // Job Templates
    /// <summary>Repository for <see cref="JobTemplate"/> reusable job blueprints; tenant-filtered with soft delete.</summary>
    public IJobTemplateRepository JobTemplates =>
        _jobTemplates ??= new JobTemplateRepository(_context);

    /// <summary>Repository for <see cref="JobTemplateItem"/> item definitions within a job template.</summary>
    public IRepository<JobTemplateItem> JobTemplateItems =>
        _jobTemplateItems ??= new Repository<JobTemplateItem>(_context);

    /// <summary>Repository for <see cref="JobTemplateItemCoat"/> coat definitions within a job template item.</summary>
    public IRepository<JobTemplateItemCoat> JobTemplateItemCoats =>
        _jobTemplateItemCoats ??= new Repository<JobTemplateItemCoat>(_context);

    /// <summary>Repository for <see cref="JobTemplateItemPrepService"/> prep-service definitions within a job template item.</summary>
    public IRepository<JobTemplateItemPrepService> JobTemplateItemPrepServices =>
        _jobTemplateItemPrepServices ??= new Repository<JobTemplateItemPrepService>(_context);

    // Purchase Orders
    /// <summary>Repository for <see cref="PurchaseOrder"/> vendor purchase orders; tenant-filtered with soft delete.</summary>
    public IPurchaseOrderRepository PurchaseOrders =>
        _purchaseOrders ??= new PurchaseOrderRepository(_context);

    /// <summary>Repository for <see cref="PurchaseOrderItem"/> line-items on a purchase order; cascade-deleted with the PO.</summary>
    public IRepository<PurchaseOrderItem> PurchaseOrderItems =>
        _purchaseOrderItems ??= new Repository<PurchaseOrderItem>(_context);

    // Oven Scheduling
    /// <summary>Repository for <see cref="OvenBatch"/> scheduled oven cure batches; tenant-filtered with soft delete.</summary>
    public IRepository<OvenBatch> OvenBatches =>
        _ovenBatches ??= new Repository<OvenBatch>(_context);

    /// <summary>Repository for <see cref="OvenBatchItem"/> job/item assignments within an oven batch.</summary>
    public IRepository<OvenBatchItem> OvenBatchItems =>
        _ovenBatchItems ??= new Repository<OvenBatchItem>(_context);

    // Invoices, Payments & Deposits
    /// <summary>Repository for <see cref="Invoice"/> customer invoices (1:1 with Job); tenant-filtered with soft delete.</summary>
    public IInvoiceRepository Invoices =>
        _invoices ??= new InvoiceRepository(_context);

    /// <summary>Repository for <see cref="InvoiceItem"/> line-items on an invoice; tenant-filtered with soft delete.</summary>
    public IRepository<InvoiceItem> InvoiceItems =>
        _invoiceItems ??= new Repository<InvoiceItem>(_context);

    /// <summary>Repository for <see cref="Payment"/> customer payment records against invoices; tenant-filtered with soft delete.</summary>
    public IRepository<Payment> Payments =>
        _payments ??= new Repository<Payment>(_context);

    /// <summary>
    /// Repository for <see cref="Deposit"/> pre-invoice deposit records.
    /// Unapplied deposits are auto-swept into <see cref="Payment"/> records when an invoice is created.
    /// </summary>
    public IRepository<Deposit> Deposits =>
        _deposits ??= new Repository<Deposit>(_context);

    // Expense Tracking / Accounts Payable
    /// <summary>Repository for <see cref="Account"/> chart-of-accounts entries; supports self-referencing parent/child hierarchy.</summary>
    public IRepository<Account> Accounts =>
        _accounts ??= new Repository<Account>(_context);

    /// <summary>Repository for <see cref="Bill"/> vendor bills (accounts payable); tenant-filtered with soft delete.</summary>
    public IBillRepository Bills =>
        _bills ??= new BillRepository(_context);

    /// <summary>Repository for <see cref="BillLineItem"/> expense line-items on a vendor bill; each assigned to a chart-of-accounts entry.</summary>
    public IRepository<BillLineItem> BillLineItems =>
        _billLineItems ??= new Repository<BillLineItem>(_context);

    /// <summary>Repository for <see cref="BillPayment"/> cash disbursement records against a vendor bill.</summary>
    public IRepository<BillPayment> BillPayments =>
        _billPayments ??= new Repository<BillPayment>(_context);

    /// <summary>Repository for <see cref="Expense"/> ad-hoc non-bill expense records; tenant-filtered with soft delete.</summary>
    public IRepository<Expense> Expenses =>
        _expenses ??= new Repository<Expense>(_context);

    // Manual Journal Entries
    /// <summary>Repository for <see cref="JournalEntry"/> double-entry manual journal entries; tenant-filtered with soft delete.</summary>
    public IRepository<JournalEntry> JournalEntries =>
        _journalEntries ??= new Repository<JournalEntry>(_context);

    /// <summary>Repository for <see cref="JournalEntryLine"/> individual debit/credit lines within a journal entry.</summary>
    public IRepository<JournalEntryLine> JournalEntryLines =>
        _journalEntryLines ??= new Repository<JournalEntryLine>(_context);

    // Vendor Credits
    /// <summary>Repository for <see cref="VendorCredit"/> credit notes received from vendors; tenant-filtered with soft delete.</summary>
    public IRepository<VendorCredit> VendorCredits =>
        _vendorCredits ??= new Repository<VendorCredit>(_context);

    /// <summary>Repository for <see cref="VendorCreditLineItem"/> expense-reversal lines on a vendor credit.</summary>
    public IRepository<VendorCreditLineItem> VendorCreditLineItems =>
        _vendorCreditLineItems ??= new Repository<VendorCreditLineItem>(_context);

    /// <summary>Repository for <see cref="VendorCreditApplication"/> records linking a vendor credit to a specific bill.</summary>
    public IRepository<VendorCreditApplication> VendorCreditApplications =>
        _vendorCreditApplications ??= new Repository<VendorCreditApplication>(_context);

    // Bank Reconciliation
    /// <summary>Repository for <see cref="BankReconciliation"/> sessions reconciling a bank account against a statement.</summary>
    public IRepository<BankReconciliation> BankReconciliations =>
        _bankReconciliations ??= new Repository<BankReconciliation>(_context);

    // Tax Rates
    /// <summary>Repository for <see cref="TaxRate"/> named tax rates used to pre-fill invoice tax percent by jurisdiction.</summary>
    public IRepository<TaxRate> TaxRates =>
        _taxRates ??= new Repository<TaxRate>(_context);

    // Recurring Transactions
    /// <summary>Repository for <see cref="RecurringTemplate"/> — saved recipes that auto-generate bills or expenses on a schedule.</summary>
    public IRepository<RecurringTemplate> RecurringTemplates =>
        _recurringTemplates ??= new Repository<RecurringTemplate>(_context);
    public IRepository<FixedAsset> FixedAssets =>
        _fixedAssets ??= new Repository<FixedAsset>(_context);
    public IRepository<FixedAssetDepreciationEntry> FixedAssetDepreciationEntries =>
        _fixedAssetDepreciationEntries ??= new Repository<FixedAssetDepreciationEntry>(_context);
    public IRepository<Budget> Budgets =>
        _budgets ??= new Repository<Budget>(_context);
    public IRepository<BudgetLine> BudgetLines =>
        _budgetLines ??= new Repository<BudgetLine>(_context);
    public IRepository<YearEndClose> YearEndCloses =>
        _yearEndCloses ??= new Repository<YearEndClose>(_context);

    /// <summary>
    /// Flushes all pending changes in the EF Core change tracker to the database.
    /// Returns the number of state entries written.
    /// <para>
    /// Internally delegates to <see cref="ApplicationDbContext.SaveChangesAsync"/> which
    /// automatically stamps <c>CreatedAt</c>, <c>UpdatedAt</c>, <c>CompanyId</c>, and audit
    /// fields on every modified entity before the SQL is sent.
    /// </para>
    /// </summary>
    public async Task<int> SaveChangesAsync()
    {
        return await _context.SaveChangesAsync();
    }

    /// <summary>
    /// Alias for <see cref="SaveChangesAsync"/>; provided so controllers can use the more
    /// expressive <c>await _unitOfWork.CompleteAsync()</c> idiom that signals intent
    /// ("I am done with this unit of work") rather than the more technical "save changes".
    /// Both methods are functionally identical.
    /// </summary>
    public async Task<int> CompleteAsync()
    {
        return await SaveChangesAsync();
    }

    /// <summary>
    /// Executes <paramref name="operation"/> inside a database transaction that is automatically
    /// committed if the operation succeeds or rolled back if it throws.
    /// <para>
    /// Uses the EF Core <c>IExecutionStrategy</c> so that the transaction is automatically
    /// retried on transient SQL errors (e.g., deadlocks) when the database provider supports it.
    /// This is the preferred approach over the manual <see cref="BeginTransactionAsync"/> /
    /// <see cref="CommitTransactionAsync"/> pair for most use cases.
    /// </para>
    /// </summary>
    /// <param name="operation">An async delegate whose work must be atomic. Do NOT call SaveChangesAsync inside — it is called automatically before commit.</param>
    public async Task ExecuteInTransactionAsync(Func<Task> operation)
    {
        var strategy = _context.Database.CreateExecutionStrategy();
        await strategy.ExecuteAsync<object?, bool>(
            null,
            async (dbCtx, state, ct) =>
            {
                await using var tx = await _context.Database.BeginTransactionAsync(ct);
                try
                {
                    await operation();
                    await _context.SaveChangesAsync(ct);
                    await tx.CommitAsync(ct);
                    return true;
                }
                catch
                {
                    await tx.RollbackAsync(ct);
                    throw;
                }
            },
            null);
    }

    /// <summary>
    /// Executes <paramref name="operation"/> inside an execution-strategy-aware database transaction
    /// and returns the result produced by the operation.
    /// <para>
    /// Identical to <see cref="ExecuteInTransactionAsync(Func{Task})"/> but for operations that
    /// produce a value (e.g., returning a newly created entity or a generated document number).
    /// SaveChangesAsync is called automatically before the transaction is committed.
    /// </para>
    /// </summary>
    /// <typeparam name="T">The type of value returned by the operation.</typeparam>
    /// <param name="operation">An async delegate that returns a value and whose work must be atomic.</param>
    /// <returns>The value returned by <paramref name="operation"/>.</returns>
    public async Task<T> ExecuteInTransactionAsync<T>(Func<Task<T>> operation)
    {
        var strategy = _context.Database.CreateExecutionStrategy();
        return await strategy.ExecuteAsync<object?, T>(
            null,
            async (dbCtx, state, ct) =>
            {
                await using var tx = await _context.Database.BeginTransactionAsync(ct);
                try
                {
                    var result = await operation();
                    await _context.SaveChangesAsync(ct);
                    await tx.CommitAsync(ct);
                    return result;
                }
                catch
                {
                    await tx.RollbackAsync(ct);
                    throw;
                }
            },
            null);
    }

    /// <summary>
    /// Detaches all tracked entities from the EF Core change tracker.
    /// <para>
    /// Use this in long-running processes (e.g., bulk import, seed data) to prevent the
    /// change tracker from accumulating thousands of entity snapshots, which would cause
    /// quadratic memory and CPU growth as EF Core compares snapshots on each SaveChanges.
    /// Not typically needed in per-request controllers because the DbContext is scoped.
    /// </para>
    /// </summary>
    public void ClearChangeTracker()
    {
        _context.ChangeTracker.Clear();
    }

    /// <summary>
    /// Starts an explicit database transaction and stores it in <c>_transaction</c>.
    /// Use this when you need to interleave multiple <see cref="SaveChangesAsync"/> calls
    /// within one atomic operation, or when you need finer control than
    /// <see cref="ExecuteInTransactionAsync(Func{Task})"/> provides.
    /// Always pair with a matching <see cref="CommitTransactionAsync"/> or
    /// <see cref="RollbackTransactionAsync"/> in a try/finally block.
    /// </summary>
    public async Task BeginTransactionAsync()
    {
        _transaction = await _context.Database.BeginTransactionAsync();
    }

    /// <summary>
    /// Saves all pending changes and commits the active transaction.
    /// If the save or commit fails the transaction is automatically rolled back and
    /// disposed, and the exception is re-thrown so callers can handle it.
    /// The <c>_transaction</c> field is nulled after disposal so the instance is safe to reuse.
    /// </summary>
    public async Task CommitTransactionAsync()
    {
        try
        {
            await SaveChangesAsync();
            if (_transaction != null)
            {
                await _transaction.CommitAsync();
            }
        }
        catch
        {
            await RollbackTransactionAsync();
            throw;
        }
        finally
        {
            if (_transaction != null)
            {
                await _transaction.DisposeAsync();
                _transaction = null;
            }
        }
    }

    /// <summary>
    /// Rolls back the active transaction (if one exists), discarding all changes made since
    /// <see cref="BeginTransactionAsync"/> was called, then disposes and nulls the transaction.
    /// Safe to call even if no transaction is active — the null check prevents an exception.
    /// </summary>
    public async Task RollbackTransactionAsync()
    {
        if (_transaction != null)
        {
            await _transaction.RollbackAsync();
            await _transaction.DisposeAsync();
            _transaction = null;
        }
    }

    /// <summary>
    /// Disposes the active transaction (if any) and the underlying <see cref="ApplicationDbContext"/>.
    /// Called automatically by the ASP.NET Core DI container at the end of each HTTP request
    /// because <c>UnitOfWork</c> is registered as a scoped service.
    /// Explicit disposal is only needed in non-DI scenarios (e.g., unit tests).
    /// </summary>
    public void Dispose()
    {
        _transaction?.Dispose();
        _context.Dispose();
    }
}
