import { Types } from "mongoose"
import { Blocking } from "../api/blockings/models"
import { Chat } from "../api/chats/models"
import { Follower } from "../api/followers/models"
import { User } from "../api/users/models"

// Toggle: set to true to actually create the missing 1-1 chats
const CREATE_CHATS = true

async function execute() {
  const users = JSON.parse(JSON.stringify(await User.find({}, { _id: 1, username: 1, selectedCommunity: 1 }).lean()))
  const followers = JSON.parse(JSON.stringify(await Follower.find({}, { follower: 1, following: 1 }).lean()))
  const chats = JSON.parse(JSON.stringify(await Chat.find({ isGroup: false }, { creator: 1, user: 1, participants: 1 }).lean()))

  // Build a set of existing 1-1 chat participant pairs for fast lookup
  // Uses both participants array AND the legacy creator/user fields
  const chatPairSet = new Set<string>()
  for (const chat of chats) {
    const ids: string[] = (chat.participants || []).map((p: any) => p.user?.toString()).filter(Boolean)
    if (ids.length === 2) {
      chatPairSet.add([ids[0], ids[1]].sort().join(":"))
    }
    // also cover chats stored via creator + user fields
    if (chat.creator && chat.user) {
      chatPairSet.add([chat.creator.toString(), chat.user.toString()].sort().join(":"))
    }
  }

  const missingPairs: { u1: any; u2: any }[] = []
  const seen = new Set<string>()

  for (const follow of followers) {
    const u1id = follow.follower?.toString()
    const u2id = follow.following?.toString()
    if (!u1id || !u2id) continue

    const pairKey = [u1id, u2id].sort().join(":")
    if (seen.has(pairKey)) continue
    seen.add(pairKey)

    if (!chatPairSet.has(pairKey)) {
      const u1 = users.find((u: any) => u._id?.toString() === u1id)
      const u2 = users.find((u: any) => u._id?.toString() === u2id)
      if (!u1 || !u2) continue
      missingPairs.push({ u1, u2 })
    }
  }

  console.log(`\nFound ${missingPairs.length} follow pair(s) without a 1-1 chat:\n`)
  for (const { u1, u2 } of missingPairs) {
    console.log(`  ${u1.username} (${u1._id})  <->  ${u2.username} (${u2._id})`)
  }

  if (!CREATE_CHATS) {
    console.log(`\nCREATE_CHATS is off — no chats were created.`)
    return
  }

  console.log(`\nCreating missing chats...\n`)
  let created = 0
  let skippedBlocked = 0

  for (const { u1, u2 } of missingPairs) {
    const u1ObjectId = new Types.ObjectId(u1._id)
    const u2ObjectId = new Types.ObjectId(u2._id)

    // skip if either user has blocked the other
    const isBlocked = await Blocking.findOne({
      $or: [
        { user: u1ObjectId, blockedBy: u2ObjectId },
        { blockedBy: u1ObjectId, user: u2ObjectId },
      ],
    })
    if (isBlocked) {
      console.log(`  SKIP (blocked): ${u1.username} <-> ${u2.username}`)
      skippedBlocked++
      continue
    }

    // use u1 (the follower) as creator
    const community = u1.selectedCommunity
    await Chat.create({
      creator: u1ObjectId,
      user: u2ObjectId,
      isGroup: false,
      community,
      communities: community ? [community] : [],
      participants: [
        { user: u1ObjectId, isAdmin: true },
        { user: u2ObjectId },
      ],
    })

    console.log(`  CREATED: ${u1.username} <-> ${u2.username}`)
    created++
  }

  console.log(`\nDone. Created: ${created}, Skipped (blocked): ${skippedBlocked}`)
}

const scriptBackfillFollowChats = {
  execute,
}

export default scriptBackfillFollowChats
