/**
 * One-off migration: consolidate Helcim payment plans from per-tier model
 * to unified Monthly/Annual Membership plans and backfill Mongo members.
 *
 * Usage:
 *   node scripts/helcim-plan-consolidation.js            # dry-run (default)
 *   node scripts/helcim-plan-consolidation.js --confirm  # execute all steps
 *   node scripts/helcim-plan-consolidation.js --mongo-only  # Mongo cleanup only (no Helcim)
 *
 * Required env: HELCIM_API_TOKEN, MONGODB_URI
 */

import dotenv from 'dotenv'
import { fileURLToPath } from 'url'
import { dirname, resolve } from 'path'
import { writeFileSync } from 'fs'
import mongoose from 'mongoose'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
dotenv.config({ path: resolve(__dirname, '../.env') })

// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------

const HELCIM_API_BASE = 'https://api.helcim.com/v2'

// Legacy plan IDs to delete
const LEGACY_PLAN_IDS = ['20162', '21596', '21597', '21598']

// Legacy plan name pattern — catch any additional per-tier plans
const LEGACY_PLAN_NAME_RE = /^Ghost Guild\s*[-–]\s*Member/i

const MONTHLY_PLAN = {
  name: 'Monthly Membership',
  recurringAmount: 15,
  billingPeriod: 'monthly',
}

const ANNUAL_PLAN = {
  name: 'Annual Membership',
  recurringAmount: 150,
  billingPeriod: 'yearly',
}

// Shape mirrors the pre-migration legacy plans (verified via backup dump).
// taxType:'customer' + missing taxCalculation/termLength caused ERR_VALIDATION_FAILED.
const HELCIM_PLAN_PAYLOAD_BASE = {
  businessName: '',
  businessEmail: '',
  description: '',
  type: 'subscription',
  status: 'active',
  currency: 'CAD',
  setupAmount: 0,
  billingPeriodIncrements: 1,
  dateBilling: 'Sign-up',
  termType: 'forever',
  freeTrialPeriod: 0,
  taxType: 'no_tax',
  taxCalculation: 'country_province',
  paymentMethod: 'card',
  isProrated: 'no',
}

// ---------------------------------------------------------------------------
// Flag parsing
// ---------------------------------------------------------------------------

const args = process.argv.slice(2)
const CONFIRM = args.includes('--confirm')
const MONGO_ONLY = args.includes('--mongo-only')

// --mongo-only implies destructive Mongo ops even without --confirm
// --confirm enables all destructive ops (Helcim + Mongo)

// ---------------------------------------------------------------------------
// Helcim helpers
// ---------------------------------------------------------------------------

function helcimHeaders() {
  const token = process.env.HELCIM_API_TOKEN
  if (!token) throw new Error('HELCIM_API_TOKEN not set in .env')
  return {
    accept: 'application/json',
    'content-type': 'application/json',
    'api-token': token,
  }
}

async function helcimGet(path) {
  const res = await fetch(`${HELCIM_API_BASE}${path}`, {
    headers: helcimHeaders(),
  })
  const body = await res.text()
  if (!res.ok) {
    throw new Error(`GET ${path} failed (${res.status}): ${body}`)
  }
  if (!body.trim()) return []
  try { return JSON.parse(body) } catch { return [] }
}

async function helcimDelete(path) {
  const res = await fetch(`${HELCIM_API_BASE}${path}`, {
    method: 'DELETE',
    headers: helcimHeaders(),
  })
  if (!res.ok) {
    const body = await res.text()
    throw new Error(`DELETE ${path} failed (${res.status}): ${body}`)
  }
  return res
}

async function helcimPost(path, payload) {
  const res = await fetch(`${HELCIM_API_BASE}${path}`, {
    method: 'POST',
    headers: helcimHeaders(),
    body: JSON.stringify(payload),
  })
  const body = await res.text()
  let parsed
  try { parsed = JSON.parse(body) } catch { parsed = body }
  return { ok: res.ok, status: res.status, body: parsed }
}

// ---------------------------------------------------------------------------
// Mongo helpers
// ---------------------------------------------------------------------------

async function connectMongo() {
  const uri = process.env.MONGODB_URI
  if (!uri) throw new Error('MONGODB_URI not set in .env')
  await mongoose.connect(uri)
}

// ---------------------------------------------------------------------------
// Timestamp helper
// ---------------------------------------------------------------------------

function safeTimestamp() {
  return new Date().toISOString().replace(/:/g, '-')
}

// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------

async function main() {
  console.log('=== Helcim Plan Consolidation' + (CONFIRM ? '' : ' (DRY RUN)') + ' ===')
  console.log(`Mode: ${CONFIRM ? 'LIVE' : 'dry-run'}`)
  console.log(`Flags: --confirm=${CONFIRM}, --mongo-only=${MONGO_ONLY}`)
  console.log()

  // -------------------------------------------------------------------------
  // Step 1: Backup
  // -------------------------------------------------------------------------
  console.log('Step 1: Backup')

  let subscriptions = []
  let plans = []
  let mongoMembers = []

  if (!MONGO_ONLY) {
    process.stdout.write('  Fetching Helcim subscriptions... ')
    const subData = await helcimGet('/subscriptions')
    subscriptions = Array.isArray(subData) ? subData : (subData.subscriptions ?? subData.data ?? [])
    console.log(`Found ${subscriptions.length} subscriptions`)

    process.stdout.write('  Fetching Helcim payment plans... ')
    const planData = await helcimGet('/payment-plans')
    plans = Array.isArray(planData) ? planData : (planData.plans ?? planData.data ?? [])
    console.log(`Found ${plans.length} plans`)
  } else {
    console.log('  [--mongo-only] Skipping Helcim backup')
  }

  // Always connect Mongo for member backup
  process.stdout.write('  Fetching Mongo members with helcimSubscriptionId... ')
  await connectMongo()
  const membersColl = mongoose.connection.collection('members')
  const rawMembers = await membersColl
    .find({ helcimSubscriptionId: { $exists: true } })
    .project({ _id: 1, email: 1, status: 1, helcimSubscriptionId: 1, contributionAmount: 1, billingCadence: 1 })
    .toArray()
  mongoMembers = rawMembers
  console.log(`Found ${mongoMembers.length} members`)

  const backupFilename = `.migration-backup-${safeTimestamp()}.json`
  const backupData = {
    timestamp: new Date().toISOString(),
    flags: { confirm: CONFIRM, mongoOnly: MONGO_ONLY },
    helcimSubscriptions: subscriptions,
    helcimPlans: plans,
    mongoMembers,
  }
  writeFileSync(backupFilename, JSON.stringify(backupData, null, 2))
  console.log(`  Backup written: ${backupFilename}`)
  console.log()

  // -------------------------------------------------------------------------
  // Step 2: Delete subscriptions
  // -------------------------------------------------------------------------
  if (!MONGO_ONLY) {
    console.log('Step 2: Delete subscriptions')
    if (!CONFIRM) {
      console.log(`  [DRY RUN] Would delete ${subscriptions.length} subscriptions:`)
      for (const sub of subscriptions) {
        const memberEmail = sub.customer?.email ?? sub.email ?? sub.customerId ?? 'unknown'
        console.log(`    - ${sub.id} (member: ${memberEmail})`)
      }
    } else {
      console.log(`  Deleting ${subscriptions.length} subscriptions...`)
      for (const sub of subscriptions) {
        try {
          await helcimDelete(`/subscriptions/${sub.id}`)
          console.log(`    [OK] Deleted subscription ${sub.id}`)
        } catch (err) {
          console.error(`    [ERROR] Failed to delete subscription ${sub.id}: ${err.message}`)
        }
      }
    }
    console.log()
  }

  // -------------------------------------------------------------------------
  // Step 3: Delete legacy plans
  // -------------------------------------------------------------------------
  if (!MONGO_ONLY) {
    console.log('Step 3: Delete legacy plans')

    // Detect any extra legacy plans by name pattern
    const extraLegacyIds = plans
      .filter((p) => {
        const idStr = String(p.id)
        return !LEGACY_PLAN_IDS.includes(idStr) && LEGACY_PLAN_NAME_RE.test(p.name)
      })
      .map((p) => String(p.id))

    if (extraLegacyIds.length > 0) {
      console.log(`  Detected additional legacy plans by name pattern: ${extraLegacyIds.join(', ')}`)
    }

    const allLegacyIds = [...new Set([...LEGACY_PLAN_IDS, ...extraLegacyIds])]

    if (!CONFIRM) {
      console.log(`  [DRY RUN] Would delete ${allLegacyIds.length} plans: ${allLegacyIds.join(', ')}`)
    } else {
      console.log(`  Deleting ${allLegacyIds.length} plans: ${allLegacyIds.join(', ')}`)
      for (const planId of allLegacyIds) {
        try {
          await helcimDelete(`/payment-plans/${planId}`)
          console.log(`    [OK] Deleted plan ${planId}`)
        } catch (err) {
          console.error(`    [ERROR] Failed to delete plan ${planId}: ${err.message}`)
        }
      }
    }
    console.log()
  }

  // -------------------------------------------------------------------------
  // Steps 4 & 5: Create new plans
  // -------------------------------------------------------------------------
  let monthlyPlanId = null
  let annualPlanId = null

  if (!MONGO_ONLY) {
    // Idempotency: check if plans already exist in backup
    const existingMonthly = plans.find((p) => p.name === MONTHLY_PLAN.name)
    const existingAnnual = plans.find((p) => p.name === ANNUAL_PLAN.name)

    // Step 4: Monthly Membership
    console.log('Step 4: Create Monthly Membership')
    const monthlyPayload = {
      ...HELCIM_PLAN_PAYLOAD_BASE,
      name: MONTHLY_PLAN.name,
      recurringAmount: MONTHLY_PLAN.recurringAmount,
      billingPeriod: MONTHLY_PLAN.billingPeriod,
    }

    if (existingMonthly) {
      monthlyPlanId = existingMonthly.id
      console.log(`  [SKIP] Plan "${MONTHLY_PLAN.name}" already exists with id ${monthlyPlanId}`)
    } else if (!CONFIRM) {
      console.log(`  [DRY RUN] Would POST /payment-plans with:`)
      console.log('   ', JSON.stringify(monthlyPayload, null, 4).split('\n').join('\n    '))
    } else {
      const wrapped = { paymentPlans: [monthlyPayload] }
      console.log(`  POSTing /payment-plans with:`)
      console.log('   ', JSON.stringify(wrapped, null, 4).split('\n').join('\n    '))
      const result = await helcimPost('/payment-plans', wrapped)
      if (!result.ok) {
        console.error(`  [ERROR] POST failed (${result.status}):`)
        console.error('  ', JSON.stringify(result.body, null, 2))
        console.error('  Aborting — fix the payload and re-run.')
        await mongoose.disconnect()
        process.exit(1)
      }
      monthlyPlanId = result.body.data?.[0]?.id ?? result.body.paymentPlans?.[0]?.id ?? result.body.id
      console.log(`  [OK] Created Monthly Membership plan id: ${monthlyPlanId}`)
    }
    console.log()

    // Step 5: Annual Membership
    console.log('Step 5: Create Annual Membership')
    const annualPayload = {
      ...HELCIM_PLAN_PAYLOAD_BASE,
      name: ANNUAL_PLAN.name,
      recurringAmount: ANNUAL_PLAN.recurringAmount,
      billingPeriod: ANNUAL_PLAN.billingPeriod,
    }

    if (existingAnnual) {
      annualPlanId = existingAnnual.id
      console.log(`  [SKIP] Plan "${ANNUAL_PLAN.name}" already exists with id ${annualPlanId}`)
    } else if (!CONFIRM) {
      console.log(`  [DRY RUN] Would POST /payment-plans with:`)
      console.log('   ', JSON.stringify(annualPayload, null, 4).split('\n').join('\n    '))
      console.log('  Note: billingPeriod="yearly" is Helcim v2 convention.')
      console.log('  If 4xx on --confirm, check the Helcim API docs for the correct field value.')
    } else {
      const wrapped = { paymentPlans: [annualPayload] }
      console.log(`  POSTing /payment-plans with:`)
      console.log('   ', JSON.stringify(wrapped, null, 4).split('\n').join('\n    '))
      const result = await helcimPost('/payment-plans', wrapped)
      if (!result.ok) {
        console.error(`  [ERROR] POST failed (${result.status}):`)
        console.error('  ', JSON.stringify(result.body, null, 2))
        console.error('  If billingPeriod is wrong, update ANNUAL_PLAN.billingPeriod and re-run.')
        console.error('  Aborting.')
        await mongoose.disconnect()
        process.exit(1)
      }
      annualPlanId = result.body.data?.[0]?.id ?? result.body.paymentPlans?.[0]?.id ?? result.body.id
      console.log(`  [OK] Created Annual Membership plan id: ${annualPlanId}`)
    }
    console.log()
  }

  // -------------------------------------------------------------------------
  // Step 6: Mongo cleanup
  // -------------------------------------------------------------------------
  const runMongoDestructive = CONFIRM || MONGO_ONLY
  console.log('Step 6: Mongo cleanup')

  if (!runMongoDestructive) {
    console.log(`  [DRY RUN] Would updateMany on ${mongoMembers.length} members:`)
    console.log('    { $set: { contributionAmount: 0, billingCadence: \'monthly\' }, $unset: { helcimSubscriptionId: \'\' } }')
    console.log('  (Status field is NOT changed — active stays active, pending_payment stays pending_payment)')
  } else {
    console.log(`  Running updateMany on ${mongoMembers.length} members with helcimSubscriptionId...`)
    const result = await membersColl.updateMany(
      { helcimSubscriptionId: { $exists: true } },
      {
        $set: { contributionAmount: 0, billingCadence: 'monthly' },
        $unset: { helcimSubscriptionId: '' },
      },
      { runValidators: false },
    )
    console.log(`  [OK] Modified ${result.modifiedCount} member(s)`)
  }
  console.log()

  // -------------------------------------------------------------------------
  // Summary
  // -------------------------------------------------------------------------
  if (!CONFIRM && !MONGO_ONLY) {
    console.log('=== To execute, re-run with --confirm ===')
    console.log('=== To run Mongo cleanup only, re-run with --mongo-only ===')
  } else {
    if (!MONGO_ONLY) {
      console.log('=== New plan IDs — copy into .env ===')
      console.log(`NUXT_HELCIM_MONTHLY_PLAN_ID=${monthlyPlanId ?? '<check backup>'}`)
      console.log(`NUXT_HELCIM_ANNUAL_PLAN_ID=${annualPlanId ?? '<check backup>'}`)
    }
    console.log('=== Migration complete ===')
  }

  await mongoose.disconnect()
}

main().catch((err) => {
  console.error('\n[FATAL]', err.message)
  mongoose.disconnect().catch(() => {})
  process.exit(1)
})
