import { __decorate, __metadata } from "tslib";
import { GraphQLError } from 'graphql';
import { Injectable, Scope } from 'graphql-modules';
import { sql } from '@pgtyped/runtime';
import { makeUUID } from '../../../shared/helpers/deterministic-uuid.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js';
import { Auth0ManagementProvider } from '../../auth/providers/auth0-management.provider.js';
import { BusinessUsersProvider } from '../../auth/providers/business-users.provider.js';
import { InvitationsProvider } from '../../auth/providers/invitations.provider.js';
import { SuperAdminProvider } from '../../auth/providers/super-admin.provider.js';
import { AdminBusinessesProvider } from '../../financial-entities/providers/admin-businesses.provider.js';
import { EntityEnsureProvider } from '../../financial-entities/providers/entity-ensure.provider.js';
const setRlsContext = sql `
  SELECT set_config('app.current_business_id', $businessId, true);
`;
const setSelfOwner = sql `
  UPDATE accounter_schema.financial_entities
  SET owner_id = $id
  WHERE id = $id;
`;
const getBootstrapBusiness = sql `
  SELECT fe.*, b.vat_number, b.hebrew_name, b.address, b.address_hebrew, b.email,
         b.website, b.phone_number, b.country, b.no_invoices_required, b.suggestion_data,
         b.can_settle_with_receipt, b.exempt_dealer, b.optional_vat,
         b.pcn874_record_type_override, b.city, b.zip_code
  FROM accounter_schema.businesses b
  INNER JOIN accounter_schema.financial_entities fe USING (id)
  WHERE b.id = $id;
`;
const getBootstrapContext = sql `
  SELECT * FROM accounter_schema.user_context
  WHERE owner_id = $ownerId;
`;
const expireActiveInvitations = sql `
  UPDATE accounter_schema.invitations
  SET expires_at = NOW(), accepted_at = NOW()
  WHERE business_id = $businessId
    AND lower(email) = lower($email)
    AND accepted_at IS NULL
    AND expires_at > NOW();
`;
let AdminOnboardingProvider = class AdminOnboardingProvider {
    db;
    entityEnsure;
    adminContextProvider;
    businessUsersProvider;
    adminBusinessesProvider;
    auth0Management;
    invitationsProvider;
    superAdminProvider;
    constructor(db, entityEnsure, adminContextProvider, businessUsersProvider, adminBusinessesProvider, auth0Management, invitationsProvider, superAdminProvider) {
        this.db = db;
        this.entityEnsure = entityEnsure;
        this.adminContextProvider = adminContextProvider;
        this.businessUsersProvider = businessUsersProvider;
        this.adminBusinessesProvider = adminBusinessesProvider;
        this.auth0Management = auth0Management;
        this.invitationsProvider = invitationsProvider;
        this.superAdminProvider = superAdminProvider;
    }
    async bootstrapNewClient(input) {
        const superAdmin = await this.superAdminProvider.requireSuperAdmin();
        return this.db.transaction(async (client) => {
            const { businessName, countryCode, locality, dateEstablished, initialAccounterYear, ownerEmail, ownerRole, } = input;
            // 0. Ensure country reference data (no RLS on countries table)
            await this.entityEnsure.ensureCountry(countryCode, countryCode, client);
            // 1. Determine the new admin entity's deterministic ID so we can set RLS context before inserting
            const adminEntityId = makeUUID('business', businessName);
            // Set RLS context — needed for all inserts via the tenant_isolation policy
            await setRlsContext.run({ businessId: adminEntityId }, client);
            // Insert financial_entity with owner_id=NULL first (allow_bootstrap_root policy allows
            // id = current_business_id). Then insert businesses, then update owner_id to self.
            await this.entityEnsure.ensureFinancialEntity({
                id: adminEntityId,
                name: businessName,
                type: 'business',
            }, client);
            await this.entityEnsure.ensureBusinessForEntity(adminEntityId, {
                ownerId: adminEntityId,
                country: countryCode,
            }, client);
            // Update owner_id to self (allow_bootstrap_owner_update RLS policy permits this)
            await setSelfOwner.run({ id: adminEntityId }, client);
            // Register as an admin-managed business (required for business_users FK)
            await this.adminBusinessesProvider.insertAdminBusiness(adminEntityId, client);
            // 2. Authority businesses
            const authorityBusinessIds = {};
            for (const name of ['VAT', 'Tax', 'Social Security']) {
                const { id } = await this.entityEnsure.ensureFinancialEntity({
                    name,
                    type: 'business',
                    ownerId: adminEntityId,
                }, client);
                authorityBusinessIds[name] = id;
                await this.entityEnsure.ensureBusinessForEntity(id, {
                    isDocumentsOptional: true,
                    ownerId: adminEntityId,
                }, client);
            }
            // 3. Authority tax categories
            const authorityTaxCategoryIds = {};
            for (const name of ['Input Vat', 'Output Vat', 'Property Output Vat', 'Tax Expenses']) {
                const { id } = await this.entityEnsure.ensureFinancialEntity({
                    name,
                    type: 'tax_category',
                    ownerId: adminEntityId,
                }, client);
                authorityTaxCategoryIds[name] = id;
                await this.entityEnsure.ensureTaxCategoryForEntity(id, { ownerId: adminEntityId }, client);
            }
            // 4. General tax categories
            const generalTaxCategoryIds = {};
            for (const name of [
                'DEFAULT (missing)',
                'Exchange Rates',
                'Income Exchange Rates',
                'Exchange Revaluation',
                'Fee',
                'General Fee',
                'Fine',
                'Untaxable Gifts',
                'Balance Cancellation',
                'Development Foreign',
                'Development Local',
                'Salary Excess Expenses',
            ]) {
                const { id } = await this.entityEnsure.ensureFinancialEntity({
                    name,
                    type: 'tax_category',
                    ownerId: adminEntityId,
                }, client);
                generalTaxCategoryIds[name] = id;
                await this.entityEnsure.ensureTaxCategoryForEntity(id, { ownerId: adminEntityId }, client);
            }
            // 5. Cross-year tax categories
            const crossYearTaxCategoryIds = {};
            for (const name of [
                'Expenses to Pay',
                'Expenses in Advance',
                'Income to Collect',
                'Income in Advance',
            ]) {
                const { id } = await this.entityEnsure.ensureFinancialEntity({
                    name,
                    type: 'tax_category',
                    ownerId: adminEntityId,
                }, client);
                crossYearTaxCategoryIds[name] = id;
                await this.entityEnsure.ensureTaxCategoryForEntity(id, { ownerId: adminEntityId }, client);
            }
            // 6. Insert user_context — dynamic column list, cannot use PgTyped
            const contextCols = {
                owner_id: adminEntityId,
                default_local_currency: 'ILS',
                default_fiat_currency_for_crypto_conversions: 'USD',
                locality: locality ?? 'ISR',
                default_tax_category_id: generalTaxCategoryIds['DEFAULT (missing)'],
                vat_business_id: authorityBusinessIds['VAT'],
                input_vat_tax_category_id: authorityTaxCategoryIds['Input Vat'],
                output_vat_tax_category_id: authorityTaxCategoryIds['Output Vat'],
                property_output_vat_tax_category_id: authorityTaxCategoryIds['Property Output Vat'],
                tax_business_id: authorityBusinessIds['Tax'],
                tax_expenses_tax_category_id: authorityTaxCategoryIds['Tax Expenses'],
                social_security_business_id: authorityBusinessIds['Social Security'],
                exchange_rate_tax_category_id: generalTaxCategoryIds['Exchange Rates'],
                income_exchange_rate_tax_category_id: generalTaxCategoryIds['Income Exchange Rates'],
                exchange_rate_revaluation_tax_category_id: generalTaxCategoryIds['Exchange Revaluation'],
                fee_tax_category_id: generalTaxCategoryIds['Fee'],
                general_fee_tax_category_id: generalTaxCategoryIds['General Fee'],
                fine_tax_category_id: generalTaxCategoryIds['Fine'],
                untaxable_gifts_tax_category_id: generalTaxCategoryIds['Untaxable Gifts'],
                balance_cancellation_tax_category_id: generalTaxCategoryIds['Balance Cancellation'],
                development_foreign_tax_category_id: generalTaxCategoryIds['Development Foreign'],
                development_local_tax_category_id: generalTaxCategoryIds['Development Local'],
                expenses_to_pay_tax_category_id: crossYearTaxCategoryIds['Expenses to Pay'],
                expenses_in_advance_tax_category_id: crossYearTaxCategoryIds['Expenses in Advance'],
                income_to_collect_tax_category_id: crossYearTaxCategoryIds['Income to Collect'],
                income_in_advance_tax_category_id: crossYearTaxCategoryIds['Income in Advance'],
                salary_excess_expenses_tax_category_id: generalTaxCategoryIds['Salary Excess Expenses'],
                ...(dateEstablished ? { date_established: dateEstablished } : {}),
                ...(initialAccounterYear ? { initial_accounter_year: initialAccounterYear } : {}),
            };
            const columns = Object.keys(contextCols).join(', ');
            const placeholders = Object.keys(contextCols)
                .map((_, i) => `$${i + 1}`)
                .join(', ');
            await client.query(`INSERT INTO accounter_schema.user_context (${columns}) VALUES (${placeholders}) ON CONFLICT (owner_id) DO NOTHING`, Object.values(contextCols));
            // 7. Create Auth0 user (blocked) + invitation
            // Expire any standing invitations so insertInvitation can create a fresh one
            await expireActiveInvitations.run({ businessId: adminEntityId, email: ownerEmail }, client);
            const auth0UserId = await this.auth0Management.createBlockedUser(ownerEmail);
            await this.businessUsersProvider.insertBusinessUser({
                userId: superAdmin.userId,
                auth0UserId: superAdmin.auth0UserId,
                roleId: ownerRole,
                ownerId: adminEntityId,
            });
            const { token: invitationToken } = await this.invitationsProvider.insertInvitation({
                email: ownerEmail,
                roleId: ownerRole,
                auth0UserId,
                invitedByUserId: superAdmin.userId,
                ownerId: adminEntityId,
            });
            // 8. Fetch business and adminContext while RLS context is still set to adminEntityId
            const [businessResults, contextResults] = await Promise.all([
                getBootstrapBusiness.run({ id: adminEntityId }, client),
                getBootstrapContext.run({ ownerId: adminEntityId }, client),
            ]);
            const business = businessResults[0];
            if (!business) {
                throw new GraphQLError('Admin business not found after bootstrap', {
                    extensions: { code: 'INTERNAL_SERVER_ERROR' },
                });
            }
            const rawContext = contextResults[0];
            if (!rawContext) {
                throw new GraphQLError('Admin context not found after bootstrap', {
                    extensions: { code: 'INTERNAL_SERVER_ERROR' },
                });
            }
            const adminContext = this.adminContextProvider.normalizeContext(rawContext);
            return {
                adminEntityId,
                invitationToken,
                business,
                adminContext,
            };
        });
    }
};
AdminOnboardingProvider = __decorate([
    Injectable({ scope: Scope.Operation }),
    __metadata("design:paramtypes", [TenantAwareDBClient,
        EntityEnsureProvider,
        AdminContextProvider,
        BusinessUsersProvider,
        AdminBusinessesProvider,
        Auth0ManagementProvider,
        InvitationsProvider,
        SuperAdminProvider])
], AdminOnboardingProvider);
export { AdminOnboardingProvider };
//# sourceMappingURL=admin-onboarding.provider.js.map