/**
 * Duo Security Sync Service
 * Orchestrates data pull from all Duo accounts (Accounts API + Admin API) into PostgreSQL.
 */

import { postgresClient } from './postgres-client';
import {
  getDuoAccountsClient,
  getDuoAdminClient,
  DuoClient,
  DuoAccount,
} from './duo-client';

export interface DuoSyncEntityResult {
  entity: string;
  account: string;
  success: boolean;
  recordsUpserted: number;
  duration: number;
  error?: string;
}

export interface DuoSyncResult {
  syncId: string;
  status: 'completed' | 'failed';
  startedAt: Date;
  completedAt: Date;
  duration: number;
  entities: DuoSyncEntityResult[];
  totalUpserted: number;
  errors: string[];
}

let currentSyncId: string | null = null;
let isSyncing = false;

export class DuoSyncService {

  isSyncInProgress(): boolean { return isSyncing; }
  getCurrentSyncId(): string | null { return currentSyncId; }

  // ── 3.4  syncAll — full orchestration ──────────────────────────────────────

  async syncAll(triggeredBy = 'system'): Promise<DuoSyncResult> {
    if (isSyncing) throw new Error('Duo sync already in progress');
    isSyncing = true;
    currentSyncId = `duo_sync_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;

    const startedAt = new Date();
    const entities: DuoSyncEntityResult[] = [];
    const errors: string[] = [];

    console.log(`[DuoSync] Starting full sync (${currentSyncId}) triggered by ${triggeredBy}`);

    try {
      const accountsClient = getDuoAccountsClient();
      const adminClient = getDuoAdminClient();

      // Step 1: sync child account list
      const accounts = await this.syncAccounts(accountsClient, entities, errors);

      // Step 2: for each child, sync all data sequentially
      for (const account of accounts) {
        console.log(`[DuoSync] Syncing child: ${account.name} (${account.account_id})`);
        await this.syncAccountData(accountsClient, account, entities, errors);
        await this.syncAuthLogs(accountsClient, account, entities, errors);
      }

      // Step 3: sync parent account using Admin API creds
      console.log(`[DuoSync] Syncing parent account`);
      await this.syncParentAccount(adminClient, entities, errors);

      // Step 4: company matching
      await this.matchCompanies(entities, errors);

    } catch (err: any) {
      console.error(`[DuoSync] Fatal error:`, err);
      errors.push(err.message);
    } finally {
      isSyncing = false;
    }

    const completedAt = new Date();
    const result: DuoSyncResult = {
      syncId: currentSyncId,
      status: errors.length > 0 ? 'failed' : 'completed',
      startedAt,
      completedAt,
      duration: completedAt.getTime() - startedAt.getTime(),
      entities,
      totalUpserted: entities.reduce((sum, e) => sum + e.recordsUpserted, 0),
      errors,
    };

    console.log(`[DuoSync] Completed in ${result.duration}ms — ${result.totalUpserted} total records, ${errors.length} error(s)`);
    currentSyncId = null;
    return result;
  }

  // ── 3.1  syncAccounts ──────────────────────────────────────────────────────

  private async syncAccounts(
    client: DuoClient,
    entities: DuoSyncEntityResult[],
    errors: string[],
  ): Promise<DuoAccount[]> {
    const start = Date.now();
    const entityName = 'duo_accounts';
    try {
      const accounts = await client.listAccounts();
      let upserted = 0;

      for (const acct of accounts) {
        // Get summary for each child
        let userCount = 0;
        let integrationCount = 0;
        try {
          const summary = await client.getAccountSummary(acct);
          userCount = summary.user_count ?? 0;
          integrationCount = summary.integration_count ?? 0;
        } catch (err: any) {
          console.warn(`[DuoSync] Could not get summary for ${acct.name}: ${err.message}`);
        }

        await postgresClient.query(`
          INSERT INTO duo_accounts (account_id, name, api_hostname, user_count, integration_count, is_parent, synced_at)
          VALUES ($1, $2, $3, $4, $5, false, NOW())
          ON CONFLICT (account_id) DO UPDATE SET
            name = EXCLUDED.name,
            api_hostname = EXCLUDED.api_hostname,
            user_count = EXCLUDED.user_count,
            integration_count = EXCLUDED.integration_count,
            synced_at = NOW()
        `, [acct.account_id, acct.name, acct.api_hostname, userCount, integrationCount]);
        upserted++;
      }

      entities.push({ entity: entityName, account: 'all', success: true, recordsUpserted: upserted, duration: Date.now() - start });
      console.log(`[DuoSync] Synced ${upserted} child accounts`);
      return accounts;
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing accounts:`, err);
      errors.push(`accounts: ${err.message}`);
      entities.push({ entity: entityName, account: 'all', success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
      return [];
    }
  }

  // ── 3.2  syncAccountData — users, phones, groups, integrations ─────────────

  private async syncAccountData(
    client: DuoClient,
    account: DuoAccount,
    entities: DuoSyncEntityResult[],
    errors: string[],
  ): Promise<void> {
    await this.syncUsers(client, account, entities, errors);
    await this.syncPhones(client, account, entities, errors);
    await this.syncGroups(client, account, entities, errors);
    await this.syncIntegrations(client, account, entities, errors);
  }

  private async syncUsers(client: DuoClient, account: DuoAccount, entities: DuoSyncEntityResult[], errors: string[]): Promise<void> {
    const start = Date.now();
    try {
      const users = await client.getUsers(account);
      let upserted = 0;
      for (const u of users) {
        await postgresClient.query(`
          INSERT INTO duo_users (user_id, duo_account_id, username, email, realname, status, is_enrolled, last_login, last_directory_sync, created, notes, phones_count, groups, aliases, enable_auto_prompt, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW())
          ON CONFLICT (user_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id,
            username = EXCLUDED.username,
            email = EXCLUDED.email,
            realname = EXCLUDED.realname,
            status = EXCLUDED.status,
            is_enrolled = EXCLUDED.is_enrolled,
            last_login = EXCLUDED.last_login,
            last_directory_sync = EXCLUDED.last_directory_sync,
            notes = EXCLUDED.notes,
            phones_count = EXCLUDED.phones_count,
            groups = EXCLUDED.groups,
            aliases = EXCLUDED.aliases,
            enable_auto_prompt = EXCLUDED.enable_auto_prompt,
            synced_at = NOW()
        `, [
          u.user_id,
          account.account_id,
          u.username,
          u.email || null,
          u.realname || null,
          u.status,
          u.is_enrolled,
          u.last_login ? new Date(u.last_login * 1000) : null,
          u.last_directory_sync ? new Date(u.last_directory_sync * 1000) : null,
          u.created ? new Date(u.created * 1000) : null,
          u.notes || null,
          u.phones?.length ?? 0,
          JSON.stringify(u.groups?.map((g: any) => ({ group_id: g.group_id, name: g.name })) ?? []),
          JSON.stringify(u.aliases ?? {}),
          u.enable_auto_prompt ?? true,
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_users', account: account.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing users for ${account.name}:`, err.message);
      errors.push(`users/${account.name}: ${err.message}`);
      entities.push({ entity: 'duo_users', account: account.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  private async syncPhones(client: DuoClient, account: DuoAccount, entities: DuoSyncEntityResult[], errors: string[]): Promise<void> {
    const start = Date.now();
    try {
      const phones = await client.getPhones(account);
      let upserted = 0;
      for (const p of phones) {
        await postgresClient.query(`
          INSERT INTO duo_phones (phone_id, duo_account_id, name, number, type, platform, model, os_version, app_version, activated, last_seen, capabilities, users, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,NOW())
          ON CONFLICT (phone_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id,
            name = EXCLUDED.name,
            number = EXCLUDED.number,
            type = EXCLUDED.type,
            platform = EXCLUDED.platform,
            model = EXCLUDED.model,
            os_version = EXCLUDED.os_version,
            app_version = EXCLUDED.app_version,
            activated = EXCLUDED.activated,
            last_seen = EXCLUDED.last_seen,
            capabilities = EXCLUDED.capabilities,
            users = EXCLUDED.users,
            synced_at = NOW()
        `, [
          p.phone_id,
          account.account_id,
          p.name || null,
          p.number || null,
          p.type || null,
          p.platform || null,
          p.model || null,
          p.os_version || null,
          p.app_version || null,
          p.activated ?? false,
          p.last_seen ? new Date(p.last_seen) : null,
          JSON.stringify(p.capabilities ?? []),
          JSON.stringify(p.users?.map((u: any) => ({ user_id: u.user_id, username: u.username })) ?? []),
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_phones', account: account.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing phones for ${account.name}:`, err.message);
      errors.push(`phones/${account.name}: ${err.message}`);
      entities.push({ entity: 'duo_phones', account: account.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  private async syncGroups(client: DuoClient, account: DuoAccount, entities: DuoSyncEntityResult[], errors: string[]): Promise<void> {
    const start = Date.now();
    try {
      const groups = await client.getGroups(account);
      let upserted = 0;
      for (const g of groups) {
        await postgresClient.query(`
          INSERT INTO duo_groups (group_id, duo_account_id, name, description, status, synced_at)
          VALUES ($1,$2,$3,$4,$5,NOW())
          ON CONFLICT (group_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id,
            name = EXCLUDED.name,
            description = EXCLUDED.description,
            status = EXCLUDED.status,
            synced_at = NOW()
        `, [
          g.group_id,
          account.account_id,
          g.name || null,
          g.desc || null,
          g.status || null,
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_groups', account: account.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing groups for ${account.name}:`, err.message);
      errors.push(`groups/${account.name}: ${err.message}`);
      entities.push({ entity: 'duo_groups', account: account.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  private async syncIntegrations(client: DuoClient, account: DuoAccount, entities: DuoSyncEntityResult[], errors: string[]): Promise<void> {
    const start = Date.now();
    try {
      const integrations = await client.getIntegrations(account);
      let upserted = 0;
      for (const i of integrations) {
        await postgresClient.query(`
          INSERT INTO duo_integrations (integration_key, duo_account_id, name, type, notes, synced_at)
          VALUES ($1,$2,$3,$4,$5,NOW())
          ON CONFLICT (integration_key) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id,
            name = EXCLUDED.name,
            type = EXCLUDED.type,
            notes = EXCLUDED.notes,
            synced_at = NOW()
        `, [
          i.integration_key,
          account.account_id,
          i.name || null,
          i.type || null,
          i.notes || null,
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_integrations', account: account.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing integrations for ${account.name}:`, err.message);
      errors.push(`integrations/${account.name}: ${err.message}`);
      entities.push({ entity: 'duo_integrations', account: account.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  // ── 3.3  syncAuthLogs — incremental ────────────────────────────────────────

  private async syncAuthLogs(
    client: DuoClient,
    account: DuoAccount,
    entities: DuoSyncEntityResult[],
    errors: string[],
    since?: number,
  ): Promise<void> {
    const start = Date.now();
    try {
      // Default: last synced timestamp or 30 days ago
      if (!since) {
        const lastRow = await postgresClient.query(
          `SELECT MAX(timestamp) as last_ts FROM duo_auth_logs WHERE duo_account_id = $1`,
          [account.account_id],
        );
        const lastTs = lastRow.rows[0]?.last_ts;
        since = lastTs ? new Date(lastTs).getTime() : Date.now() - 30 * 24 * 60 * 60 * 1000;
      }

      const logs = await client.getAuthLogs(since, account);
      let upserted = 0;
      for (const l of logs) {
        await postgresClient.query(`
          INSERT INTO duo_auth_logs (txid, duo_account_id, timestamp, user_name, user_id, factor, result, reason, application_name, application_key, access_device_ip, access_device_location, auth_device_ip, auth_device_name, event_type, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW())
          ON CONFLICT (txid) DO NOTHING
        `, [
          l.txid,
          account.account_id,
          new Date(l.timestamp * 1000),
          l.user?.name || null,
          l.user?.key || null,
          l.factor || null,
          l.result || null,
          l.reason || null,
          l.application?.name || null,
          l.application?.key || null,
          l.access_device?.ip || null,
          l.access_device?.location ? JSON.stringify(l.access_device.location) : null,
          l.auth_device?.ip || null,
          l.auth_device?.name || null,
          l.event_type || null,
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_auth_logs', account: account.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing auth logs for ${account.name}:`, err.message);
      errors.push(`auth_logs/${account.name}: ${err.message}`);
      entities.push({ entity: 'duo_auth_logs', account: account.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  // ── Parent account sync using DUOADMIN creds ───────────────────────────────

  private async syncParentAccount(
    adminClient: DuoClient,
    entities: DuoSyncEntityResult[],
    errors: string[],
  ): Promise<void> {
    const parentAccountId = 'PARENT_WULF';
    const parentHost = process.env.DUOADMIN_API_HOSTNAME!;

    // Upsert parent account row
    try {
      const summary = await adminClient.getAccountSummary();
      await postgresClient.query(`
        INSERT INTO duo_accounts (account_id, name, api_hostname, user_count, integration_count, is_parent, synced_at)
        VALUES ($1, 'Wulf Consulting (Parent)', $2, $3, $4, true, NOW())
        ON CONFLICT (account_id) DO UPDATE SET
          user_count = EXCLUDED.user_count,
          integration_count = EXCLUDED.integration_count,
          synced_at = NOW()
      `, [parentAccountId, parentHost, summary.user_count, summary.integration_count]);
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing parent summary:`, err.message);
      errors.push(`parent/summary: ${err.message}`);
    }

    // Create a pseudo DuoAccount for the parent so we can reuse syncAccountData/syncAuthLogs
    const parentAccount: DuoAccount = { account_id: parentAccountId, api_hostname: parentHost, name: 'Wulf Consulting (Parent)' };

    // Sync users, phones, groups, integrations using adminClient (no child override needed)
    await this.syncParentEntity('users', async () => {
      const users = await adminClient.getUsers();
      let upserted = 0;
      for (const u of users) {
        await postgresClient.query(`
          INSERT INTO duo_users (user_id, duo_account_id, username, email, realname, status, is_enrolled, last_login, last_directory_sync, created, notes, phones_count, groups, aliases, enable_auto_prompt, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW())
          ON CONFLICT (user_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id, username = EXCLUDED.username, email = EXCLUDED.email,
            realname = EXCLUDED.realname, status = EXCLUDED.status, is_enrolled = EXCLUDED.is_enrolled,
            last_login = EXCLUDED.last_login, last_directory_sync = EXCLUDED.last_directory_sync,
            notes = EXCLUDED.notes, phones_count = EXCLUDED.phones_count, groups = EXCLUDED.groups,
            aliases = EXCLUDED.aliases, enable_auto_prompt = EXCLUDED.enable_auto_prompt, synced_at = NOW()
        `, [
          u.user_id, parentAccountId, u.username, u.email || null, u.realname || null,
          u.status, u.is_enrolled,
          u.last_login ? new Date(u.last_login * 1000) : null,
          u.last_directory_sync ? new Date(u.last_directory_sync * 1000) : null,
          u.created ? new Date(u.created * 1000) : null,
          u.notes || null, u.phones?.length ?? 0,
          JSON.stringify(u.groups?.map((g: any) => ({ group_id: g.group_id, name: g.name })) ?? []),
          JSON.stringify(u.aliases ?? {}), u.enable_auto_prompt ?? true,
        ]);
        upserted++;
      }
      return upserted;
    }, parentAccount.name, entities, errors);

    await this.syncParentEntity('phones', async () => {
      const phones = await adminClient.getPhones();
      let upserted = 0;
      for (const p of phones) {
        await postgresClient.query(`
          INSERT INTO duo_phones (phone_id, duo_account_id, name, number, type, platform, model, os_version, app_version, activated, last_seen, capabilities, users, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,NOW())
          ON CONFLICT (phone_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id, name = EXCLUDED.name, number = EXCLUDED.number,
            type = EXCLUDED.type, platform = EXCLUDED.platform, model = EXCLUDED.model,
            os_version = EXCLUDED.os_version, app_version = EXCLUDED.app_version,
            activated = EXCLUDED.activated, last_seen = EXCLUDED.last_seen,
            capabilities = EXCLUDED.capabilities, users = EXCLUDED.users, synced_at = NOW()
        `, [
          p.phone_id, parentAccountId, p.name || null, p.number || null, p.type || null,
          p.platform || null, p.model || null, p.os_version || null, p.app_version || null,
          p.activated ?? false, p.last_seen ? new Date(p.last_seen) : null,
          JSON.stringify(p.capabilities ?? []),
          JSON.stringify(p.users?.map((u: any) => ({ user_id: u.user_id, username: u.username })) ?? []),
        ]);
        upserted++;
      }
      return upserted;
    }, parentAccount.name, entities, errors);

    await this.syncParentEntity('groups', async () => {
      const groups = await adminClient.getGroups();
      let upserted = 0;
      for (const g of groups) {
        await postgresClient.query(`
          INSERT INTO duo_groups (group_id, duo_account_id, name, description, status, synced_at)
          VALUES ($1,$2,$3,$4,$5,NOW())
          ON CONFLICT (group_id) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id, name = EXCLUDED.name,
            description = EXCLUDED.description, status = EXCLUDED.status, synced_at = NOW()
        `, [g.group_id, parentAccountId, g.name || null, g.desc || null, g.status || null]);
        upserted++;
      }
      return upserted;
    }, parentAccount.name, entities, errors);

    await this.syncParentEntity('integrations', async () => {
      const integrations = await adminClient.getIntegrations();
      let upserted = 0;
      for (const i of integrations) {
        await postgresClient.query(`
          INSERT INTO duo_integrations (integration_key, duo_account_id, name, type, notes, synced_at)
          VALUES ($1,$2,$3,$4,$5,NOW())
          ON CONFLICT (integration_key) DO UPDATE SET
            duo_account_id = EXCLUDED.duo_account_id, name = EXCLUDED.name,
            type = EXCLUDED.type, notes = EXCLUDED.notes, synced_at = NOW()
        `, [i.integration_key, parentAccountId, i.name || null, i.type || null, i.notes || null]);
        upserted++;
      }
      return upserted;
    }, parentAccount.name, entities, errors);

    // Auth logs for parent
    const start = Date.now();
    try {
      const lastRow = await postgresClient.query(
        `SELECT MAX(timestamp) as last_ts FROM duo_auth_logs WHERE duo_account_id = $1`,
        [parentAccountId],
      );
      const lastTs = lastRow.rows[0]?.last_ts;
      const since = lastTs ? new Date(lastTs).getTime() : Date.now() - 30 * 24 * 60 * 60 * 1000;
      const logs = await adminClient.getAuthLogs(since);
      let upserted = 0;
      for (const l of logs) {
        await postgresClient.query(`
          INSERT INTO duo_auth_logs (txid, duo_account_id, timestamp, user_name, user_id, factor, result, reason, application_name, application_key, access_device_ip, access_device_location, auth_device_ip, auth_device_name, event_type, synced_at)
          VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW())
          ON CONFLICT (txid) DO NOTHING
        `, [
          l.txid, parentAccountId, new Date(l.timestamp * 1000),
          l.user?.name || null, l.user?.key || null, l.factor || null,
          l.result || null, l.reason || null,
          l.application?.name || null, l.application?.key || null,
          l.access_device?.ip || null,
          l.access_device?.location ? JSON.stringify(l.access_device.location) : null,
          l.auth_device?.ip || null, l.auth_device?.name || null, l.event_type || null,
        ]);
        upserted++;
      }
      entities.push({ entity: 'duo_auth_logs', account: parentAccount.name, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing parent auth logs:`, err.message);
      errors.push(`auth_logs/parent: ${err.message}`);
      entities.push({ entity: 'duo_auth_logs', account: parentAccount.name, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  private async syncParentEntity(
    entityName: string,
    fn: () => Promise<number>,
    accountName: string,
    entities: DuoSyncEntityResult[],
    errors: string[],
  ): Promise<void> {
    const start = Date.now();
    try {
      const upserted = await fn();
      entities.push({ entity: `duo_${entityName}`, account: accountName, success: true, recordsUpserted: upserted, duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error syncing parent ${entityName}:`, err.message);
      errors.push(`${entityName}/parent: ${err.message}`);
      entities.push({ entity: `duo_${entityName}`, account: accountName, success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }

  // ── 3.5  Company matching ──────────────────────────────────────────────────

  private async matchCompanies(
    entities: DuoSyncEntityResult[],
    errors: string[],
  ): Promise<void> {
    const start = Date.now();
    try {
      // Exact match first
      await postgresClient.query(`
        UPDATE duo_accounts da
        SET autotask_company_id = c.id
        FROM companies c
        WHERE da.autotask_company_id IS NULL
          AND da.is_parent = false
          AND LOWER(TRIM(da.name)) = LOWER(TRIM(c.company_name))
      `);

      // Case-insensitive containment (company name contains duo account name or vice versa)
      await postgresClient.query(`
        UPDATE duo_accounts da
        SET autotask_company_id = sub.company_id
        FROM (
          SELECT DISTINCT ON (da2.account_id) da2.account_id, c.id as company_id
          FROM duo_accounts da2
          JOIN companies c ON (
            LOWER(c.company_name) LIKE '%' || LOWER(TRIM(da2.name)) || '%'
            OR LOWER(TRIM(da2.name)) LIKE '%' || LOWER(TRIM(c.company_name)) || '%'
          )
          WHERE da2.autotask_company_id IS NULL AND da2.is_parent = false
          ORDER BY da2.account_id, LENGTH(c.company_name) ASC
        ) sub
        WHERE da.account_id = sub.account_id
      `);

      const matched = await postgresClient.query(`
        SELECT COUNT(*) as matched FROM duo_accounts WHERE autotask_company_id IS NOT NULL AND is_parent = false
      `);
      const total = await postgresClient.query(`
        SELECT COUNT(*) as total FROM duo_accounts WHERE is_parent = false
      `);

      console.log(`[DuoSync] Company matching: ${matched.rows[0].matched}/${total.rows[0].total} accounts matched`);
      entities.push({ entity: 'company_matching', account: 'all', success: true, recordsUpserted: parseInt(matched.rows[0].matched), duration: Date.now() - start });
    } catch (err: any) {
      console.error(`[DuoSync] Error matching companies:`, err.message);
      errors.push(`company_matching: ${err.message}`);
      entities.push({ entity: 'company_matching', account: 'all', success: false, recordsUpserted: 0, duration: Date.now() - start, error: err.message });
    }
  }
}

export const duoSyncService = new DuoSyncService();
