import assert from 'assert';
import { db } from '../src/db/client';
import {
  BillingService,
  canUseFeature,
  assertCanUseFeature,
  FeatureAccessError,
  checkPlanLimits,
} from '../src/lib/shopify/billing';

let total = 0;
let passed = 0;

async function test(name: string, fn: () => Promise<void>) {
  total++;
  try {
    await fn();
    console.log(`  ✓ ${name}`);
    passed++;
  } catch (err: any) {
    console.error(`  ✕ ${name}:`, err.message || err);
    if (err.stack) {
      console.error(err.stack.split('\n').slice(1, 4).join('\n'));
    }
  }
}

async function runBillingVerificationSuite() {
  console.log('\n======================================================');
  console.log('🧪 RUNNING SHOPIFY BILLING SUITE (CONVERSECART REFERENCE)');
  console.log('======================================================\n');

  console.log('📦 1. Feature Entitlements & Plan Capability Gating:');

  await test('Basic plan cannot use CAPI tracking or supplementary feeds', async () => {
    assert.strictEqual(canUseFeature('basic', 'meta.capi_tracking'), false);
    assert.strictEqual(canUseFeature('basic', 'meta.supplementary_feeds'), false);
    assert.strictEqual(canUseFeature('basic', 'meta.catalog_unlimited'), false);
    assert.strictEqual(canUseFeature('basic', 'meta.dedicated_manager'), false);
  });

  await test('Growth plan can use CAPI, Multi-Pixel, but not Unlimited Catalog', async () => {
    assert.strictEqual(canUseFeature('growth', 'meta.capi_tracking'), true);
    assert.strictEqual(canUseFeature('growth', 'meta.pixel_multi'), true);
    assert.strictEqual(canUseFeature('growth', 'meta.custom_titles'), true);
    assert.strictEqual(canUseFeature('growth', 'meta.catalog_unlimited'), false);
    assert.strictEqual(canUseFeature('growth', 'meta.dedicated_manager'), false);
  });

  await test('Accelerate plan has unlimited access across all capabilities', async () => {
    assert.strictEqual(canUseFeature('accelerate', 'meta.capi_tracking'), true);
    assert.strictEqual(canUseFeature('accelerate', 'meta.catalog_unlimited'), true);
    assert.strictEqual(canUseFeature('accelerate', 'meta.ad_campaigns_unlimited'), true);
    assert.strictEqual(canUseFeature('accelerate', 'meta.website_audit'), true);
    assert.strictEqual(canUseFeature('accelerate', 'meta.dedicated_manager'), true);
  });

  await test('assertCanUseFeature throws FeatureAccessError (HTTP 403) on unauthorized feature', async () => {
    let thrown = false;
    try {
      assertCanUseFeature('basic', 'meta.capi_tracking');
    } catch (err: any) {
      thrown = true;
      assert.ok(err instanceof FeatureAccessError);
      assert.strictEqual(err.statusCode, 403);
      assert.strictEqual(err.code, 'FEATURE_NOT_AVAILABLE');
    }
    assert.ok(thrown, 'Should throw FeatureAccessError');
  });

  await test('checkPlanLimits restricts Basic tier from CAPI and SKU overages', async () => {
    const testShopId = 'shop_test_limits_' + Date.now();
    const nowStr = new Date().toISOString();
    await db.upsertShop({
      id: testShopId,
      shopify_domain: `limits-${Date.now()}.myshopify.com`,
      access_token_encrypted: 'mock_token',
      scopes: ['read_products'],
      installed_at: nowStr,
      created_at: nowStr,
      updated_at: nowStr,
      status: 'installed',
      plan: 'basic',
      plan_custom_sku_limit: 100,
    });

    const capiCheck = await checkPlanLimits(testShopId, 'capi_event');
    assert.strictEqual(capiCheck.allowed, false, 'Basic tier must not be allowed to dispatch CAPI');

    const skuCheck = await checkPlanLimits(testShopId, 'upload_skus', 50);
    assert.strictEqual(skuCheck.allowed, true, '50 SKUs is within 100 limit');

    const skuOverflow = await checkPlanLimits(testShopId, 'upload_skus', 150);
    assert.strictEqual(skuOverflow.allowed, false, '150 SKUs must exceed 100 limit');
  });

  console.log('\n📦 2. Subscription Creation Flow (Shopify GraphQL & Free Tier):');

  const timestamp = Date.now();
  const testDomain = `billing-test-${timestamp}.myshopify.com`;
  const testShopId = `shop_billing_${timestamp}`;

  await test('Free plan selection creates $0 subscription without remote charge', async () => {
    const nowStr = new Date().toISOString();
    await db.upsertShop({
      id: testShopId,
      shopify_domain: testDomain,
      access_token_encrypted: 'mock_token',
      scopes: ['read_products'],
      installed_at: nowStr,
      created_at: nowStr,
      updated_at: nowStr,
      status: 'installed',
      plan: 'growth',
      monthly_revenue: 13,
    });

    const res = await BillingService.createSubscription({
      shopDomainOrId: testShopId,
      plan: 'basic',
    });

    assert.strictEqual(res.plan, 'basic');
    assert.strictEqual(res.price, 0);
    assert.strictEqual(res.status, 'active');

    const updatedShop = await db.getShopById(testShopId);
    assert.strictEqual(updatedShop?.plan, 'basic');
    assert.strictEqual(updatedShop?.subscription_status, 'free');
    assert.strictEqual(updatedShop?.monthly_revenue, 0);

    const sub = await db.getSubscriptionByShopId(testShopId);
    assert.ok(sub);
    assert.strictEqual(sub?.plan_id, 'basic');
    assert.strictEqual(sub?.price, 0);
  });

  await test('Paid plan selection generates confirmation URL and pending/trial record', async () => {
    const res = await BillingService.createSubscription({
      shopDomainOrId: testShopId,
      plan: 'growth',
    });

    assert.strictEqual(res.plan, 'growth');
    assert.strictEqual(res.price, 13);
    assert.ok(res.confirmationUrl, 'Should return confirmationUrl');
    assert.ok(res.subscriptionId, 'Should return subscriptionId');

    const sub = await db.getSubscriptionByShopId(testShopId);
    assert.ok(sub);
    assert.strictEqual(sub?.plan_id, 'growth');
    assert.strictEqual(sub?.price, 13);
    assert.strictEqual(sub?.trial_days, 14);

    const billingEvents = await db.getBillingEventsByShopId(testShopId);
    assert.ok(billingEvents.length >= 1);
  });

  await test('Accelerate plan selection ($99/mo) computes correct tier details', async () => {
    const res = await BillingService.createSubscription({
      shopDomainOrId: testShopId,
      plan: 'accelerate',
    });

    assert.strictEqual(res.plan, 'accelerate');
    assert.strictEqual(res.price, 99);
    assert.ok(res.confirmationUrl?.includes('plan=accelerate'));
  });

  console.log('\n📦 3. Authoritative Sync & Remote Subscription Verification:');

  await test('Authoritative sync sets store to Basic (Free) when Shopify has no active charge', async () => {
    // Calling sync on a store with non-existent live Shopify token
    const planInfo = await BillingService.syncSubscription(testShopId);

    assert.strictEqual(planInfo.plan, 'basic');
    assert.strictEqual(planInfo.status, 'free');
    assert.strictEqual(planInfo.price, 0);

    const shop = await db.getShopById(testShopId);
    assert.strictEqual(shop?.plan, 'basic');
    assert.strictEqual(shop?.subscription_status, 'free');
    assert.strictEqual(shop?.monthly_revenue, 0);
  });

  await test('Subscription cancellation reverts shop to basic and records cancellation event', async () => {
    const nowStr = new Date().toISOString();
    // Give store temporary active status
    await db.upsertShop({
      id: testShopId,
      shopify_domain: testDomain,
      access_token_encrypted: 'mock_token',
      scopes: ['read_products'],
      installed_at: nowStr,
      created_at: nowStr,
      updated_at: nowStr,
      status: 'installed',
      plan: 'accelerate',
      monthly_revenue: 99,
      subscription_status: 'active',
    });

    await BillingService.cancelSubscription(testShopId);

    const shop = await db.getShopById(testShopId);
    assert.strictEqual(shop?.plan, 'basic');
    assert.strictEqual(shop?.subscription_status, 'free');
    assert.strictEqual(shop?.monthly_revenue, 0);

    const events = await db.getBillingEventsByShopId(testShopId);
    const cancelEvt = events.find((e) => e.event_type === 'charge_cancelled');
    assert.ok(cancelEvt, 'Must record charge_cancelled billing event');
  });

  console.log('\n📦 4. Store Subscription Status & Plan Details DTO:');

  await test('getActiveSubscription returns complete CurrentPlanInfo DTO', async () => {
    const info = await BillingService.getActiveSubscription(testShopId);

    assert.strictEqual(info.shopDomain, testDomain);
    assert.strictEqual(info.plan, 'basic');
    assert.strictEqual(info.price, 0);
    assert.ok(info.pricingPlansUrl.includes('admin.shopify.com'));
    assert.ok(Array.isArray(info.features));
    assert.ok(info.features.length > 0);
  });

  console.log('\n======================================================');
  console.log(`🎉 SHOPIFY BILLING SUITE COMPLETED: ${passed}/${total} PASSED, ${total - passed} FAILED`);
  console.log('======================================================\n');

  if (passed !== total) {
    process.exit(1);
  }
}

runBillingVerificationSuite().catch((err) => {
  console.error('Test runner failure:', err);
  process.exit(1);
});
