/**
 * Migration Script: Community Connections
 *
 * Migrates existing member peer support and tag data to the new
 * communityConnections schema.
 *
 * What this does:
 * 1. Builds a slug lookup from all cooperative tags in the database
 * 2. For each member with offering.tags or lookingFor.tags:
 *    - Maps offering.tags  → communityConnections.topics with state "help"
 *    - Maps lookingFor.tags → communityConnections.topics with state "seeking"
 * 3. Copies peerSupport.enabled → communityConnections.offerPeerSupport
 * 4. Copies peerSupport.availability, peerSupport.personalMessage,
 *    peerSupport.slackUsername → communityConnections.availability,
 *    .personalMessage, .slackHandle
 * 5. Does NOT delete old fields (non-destructive)
 *
 * Safe to re-run: skips members whose communityConnections is already populated.
 */

import 'dotenv/config'
import mongoose from 'mongoose'
import Tag from '../models/tag.js'
import Member from '../models/member.js'
import { connectDB } from '../utils/mongoose.js'

async function buildCoopTagLookup() {
  const coopTags = await Tag.find({ pool: 'cooperative', active: true }).lean()
  // Maps normalized label → slug, and slug → slug (for direct slug matches)
  const lookup = new Map()
  for (const tag of coopTags) {
    lookup.set(tag.label.toLowerCase(), tag.slug)
    lookup.set(tag.slug.toLowerCase(), tag.slug)
  }
  return lookup
}

function resolveTagSlugs(rawTags, lookup) {
  const matched = []
  const unmatched = []
  for (const raw of rawTags) {
    const normalized = raw.toLowerCase().trim()
    if (lookup.has(normalized)) {
      matched.push(lookup.get(normalized))
    } else {
      unmatched.push(raw)
    }
  }
  return { matched, unmatched }
}

async function migrateCommunityConnections() {
  await connectDB()

  console.log('Building cooperative tag lookup...')
  const coopLookup = await buildCoopTagLookup()
  console.log(`  Loaded ${coopLookup.size / 2} cooperative tags`)

  // Find members that have anything to migrate and haven't been migrated yet.
  // A member is considered already migrated if communityConnections.topics has entries
  // or offerPeerSupport is explicitly set.
  const members = await Member.find({
    $or: [
      { 'offering.tags': { $exists: true, $ne: [] } },
      { 'lookingFor.tags': { $exists: true, $ne: [] } },
      { 'peerSupport.enabled': { $exists: true } },
      { 'peerSupport.availability': { $exists: true } },
      { 'peerSupport.personalMessage': { $exists: true } },
      { 'peerSupport.slackUsername': { $exists: true } },
    ],
  }).lean()

  console.log(`\nFound ${members.length} member(s) with data to migrate`)

  let migratedCount = 0
  let skippedCount = 0
  let totalTagsMatched = 0
  const allUnmatched = []

  for (const member of members) {
    const label = `${member.name || member.email} (${member._id})`

    // Skip if already migrated (topics array has entries or offerPeerSupport is set)
    const cc = member.communityConnections || {}
    const alreadyMigrated =
      (cc.topics && cc.topics.length > 0) ||
      cc.offerPeerSupport === true ||
      cc.availability ||
      cc.slackHandle ||
      cc.personalMessage

    if (alreadyMigrated) {
      console.log(`  skip  ${label} — communityConnections already populated`)
      skippedCount++
      continue
    }

    const topics = []
    const memberUnmatched = []

    // Map offering.tags → state "help"
    const offeringTags = member.offering?.tags || []
    if (offeringTags.length > 0) {
      const { matched, unmatched } = resolveTagSlugs(offeringTags, coopLookup)
      for (const slug of matched) {
        // Avoid duplicates
        if (!topics.find((t) => t.tagSlug === slug)) {
          topics.push({ tagSlug: slug, state: 'help' })
        }
      }
      totalTagsMatched += matched.length
      if (unmatched.length > 0) {
        memberUnmatched.push(...unmatched.map((t) => `offering: "${t}"`))
      }
    }

    // Map lookingFor.tags → state "seeking"
    const lookingForTags = member.lookingFor?.tags || []
    if (lookingForTags.length > 0) {
      const { matched, unmatched } = resolveTagSlugs(lookingForTags, coopLookup)
      for (const slug of matched) {
        const existing = topics.find((t) => t.tagSlug === slug)
        if (existing) {
          // Upgrade "help" to "seeking" if it appears in both (or keep as-is — use seeking)
          existing.state = 'seeking'
        } else {
          topics.push({ tagSlug: slug, state: 'seeking' })
        }
      }
      totalTagsMatched += matched.length
      if (unmatched.length > 0) {
        memberUnmatched.push(...unmatched.map((t) => `lookingFor: "${t}"`))
      }
    }

    if (memberUnmatched.length > 0) {
      allUnmatched.push({ member: label, tags: memberUnmatched })
    }

    // Build communityConnections update
    const ccUpdate = {}

    if (topics.length > 0) {
      ccUpdate['communityConnections.topics'] = topics
    }

    if (typeof member.peerSupport?.enabled === 'boolean') {
      ccUpdate['communityConnections.offerPeerSupport'] = member.peerSupport.enabled
    }

    if (member.peerSupport?.availability) {
      ccUpdate['communityConnections.availability'] = member.peerSupport.availability
    }

    if (member.peerSupport?.personalMessage) {
      ccUpdate['communityConnections.personalMessage'] = member.peerSupport.personalMessage
    }

    if (member.peerSupport?.slackUsername) {
      ccUpdate['communityConnections.slackHandle'] = member.peerSupport.slackUsername
    }

    if (Object.keys(ccUpdate).length === 0) {
      console.log(`  skip  ${label} — nothing to migrate`)
      skippedCount++
      continue
    }

    await Member.findByIdAndUpdate(
      member._id,
      { $set: ccUpdate },
      { runValidators: false }
    )

    console.log(
      `  migrated  ${label}` +
        (topics.length > 0 ? ` — ${topics.length} topic(s)` : '') +
        (memberUnmatched.length > 0 ? ` — ${memberUnmatched.length} unmatched` : '')
    )
    migratedCount++
  }

  console.log('\n=== Migration Summary ===')
  console.log(`  Total candidates:  ${members.length}`)
  console.log(`  Migrated:          ${migratedCount}`)
  console.log(`  Skipped:           ${skippedCount}`)
  console.log(`  Tags matched:      ${totalTagsMatched}`)

  if (allUnmatched.length > 0) {
    console.log(`\n  Unmatched tags (${allUnmatched.length} member(s)):`)
    for (const { member, tags } of allUnmatched) {
      console.log(`    ${member}`)
      for (const t of tags) {
        console.log(`      - ${t}`)
      }
    }
  } else {
    console.log('  Unmatched tags:    none')
  }
}

migrateCommunityConnections()
  .then(() => {
    console.log('\nMigration completed successfully')
    process.exit(0)
  })
  .catch((err) => {
    console.error('\nMigration failed:', err)
    process.exit(1)
  })
  .finally(() => {
    mongoose.connection.close()
  })
