/**
 * Shopify Expiring Offline Access Token Migration Script
 * Migrates legacy non-expiring offline tokens to expiring offline tokens with refresh tokens (RFC 7523 / Shopify 2026).
 *
 * Usage:
 *   npx tsx -r dotenv/config scripts/migrate-shopify-tokens.ts
 */

import { db } from '../src/db/client';
import { decrypt, encrypt } from '../src/lib/crypto/encryption';
import { exchangeLegacyTokenForExpiring } from '../src/lib/shopify/oauth';
import { getShopifyTokenStatus } from '../src/lib/shopify/token-manager';

async function runMigration() {
  console.log('===============================================================');
  console.log('🚀 Shopify Expiring Offline Access Token Migration & Audit');
  console.log('===============================================================\n');

  // 1. Initialize DB and ensure all required schema columns exist
  console.log('📦 Step 1: Checking database schema...');
  await db.initialize();
  console.log('   ✓ Columns verified: access_token_encrypted, refresh_token_encrypted, token_expires_at, refresh_token_expires_at, token_updated_at\n');

  // 2. Fetch all shops
  console.log('🔍 Step 2: Auditing registered Shopify stores...');
  const shops = await db.getAllShops();
  console.log(`   Found ${shops.length} store record(s) in database.\n`);

  let alreadyExpiringCount = 0;
  let migratedCount = 0;
  let skippedMockCount = 0;
  let reauthRequiredCount = 0;

  for (const shop of shops) {
    const domain = shop.shopify_domain;
    console.log(`▶ Inspecting: ${domain}`);

    const status = await getShopifyTokenStatus(domain);

    if (status.isExpiringToken && status.hasRefreshToken) {
      console.log(`   ✓ Already compliant with Expiring Offline Tokens.`);
      console.log(`     Access token expires at: ${status.tokenExpiresAt}`);
      console.log(`     Refresh token expires at: ${status.refreshTokenExpiresAt || 'Standard 90-day window'}`);
      console.log(`     Token last updated: ${status.tokenUpdatedAt}`);
      alreadyExpiringCount++;
      continue;
    }

    if (!shop.access_token_encrypted) {
      console.log(`   ⚠ No access token found in database for store. Re-authorization required.`);
      reauthRequiredCount++;
      continue;
    }

    let plainToken = '';
    try {
      plainToken = decrypt(shop.access_token_encrypted);
    } catch (decErr: any) {
      console.log(`   ✗ Decryption error for store credentials: ${decErr.message}`);
      reauthRequiredCount++;
      continue;
    }

    if (!plainToken || plainToken.startsWith('mock_') || plainToken.startsWith('shpat_mock_') || plainToken.startsWith('shpat_demo_')) {
      console.log(`   ℹ Mock or test environment token detected. Preserved safely.`);
      skippedMockCount++;
      continue;
    }

    // Attempt token exchange migration
    console.log(`   ⚡ Migrating legacy offline token to expiring token via Shopify Token Exchange API...`);
    try {
      const appConfig = await db.getAppConfigurationByDomain(domain);
      let clientSecret = '';
      if (appConfig?.shopify_api_secret_encrypted) {
        try { clientSecret = decrypt(appConfig.shopify_api_secret_encrypted); } catch {}
      }
      if (!clientSecret) clientSecret = process.env.SHOPIFY_API_SECRET || '';
      const clientId = appConfig?.shopify_api_key || process.env.SHOPIFY_API_KEY || '';

      const exchangeResult = await exchangeLegacyTokenForExpiring(domain, plainToken, clientId, clientSecret);
      const newExpiresIn = exchangeResult.expires_in || 86400;
      const now = new Date();
      const newExpiresAt = new Date(now.getTime() + newExpiresIn * 1000).toISOString();
      const newRefreshExpiresAt = exchangeResult.refresh_token_expires_in
        ? new Date(now.getTime() + exchangeResult.refresh_token_expires_in * 1000).toISOString()
        : new Date(now.getTime() + 90 * 86400 * 1000).toISOString();
      const tokenUpdatedAt = now.toISOString();

      const updated = {
        ...shop,
        access_token_encrypted: encrypt(exchangeResult.access_token),
        refresh_token_encrypted: exchangeResult.refresh_token ? encrypt(exchangeResult.refresh_token) : null,
        token_expires_at: newExpiresAt,
        refresh_token_expires_at: newRefreshExpiresAt,
        token_updated_at: tokenUpdatedAt,
        updated_at: tokenUpdatedAt,
      };

      await db.upsertShop(updated);
      console.log(`   ✓ Successfully migrated store ${domain} to Expiring Offline Tokens!`);
      console.log(`     New token expires at: ${newExpiresAt}`);
      console.log(`     Refresh token expires at: ${newRefreshExpiresAt}`);
      migratedCount++;
    } catch (migErr: any) {
      console.log(`   ⚠ Migration note for ${domain}: ${migErr.message}`);
      console.log(`     (Store will continue functioning and can refresh or re-authorize naturally)`);
      reauthRequiredCount++;
    }
  }

  console.log('\n===============================================================');
  console.log('📊 Migration & Compliance Summary');
  console.log('===============================================================');
  console.log(`Total stores audited:                     ${shops.length}`);
  console.log(`Already compliant with Expiring Tokens:   ${alreadyExpiringCount}`);
  console.log(`Successfully migrated during this run:    ${migratedCount}`);
  console.log(`Mock / local test stores:                 ${skippedMockCount}`);
  console.log(`Stores needing re-auth or app update:     ${reauthRequiredCount}`);
  console.log('===============================================================\n');

  process.exit(0);
}

runMigration().catch(err => {
  console.error('Fatal error during migration:', err);
  process.exit(1);
});
