import { Types } from 'mongoose'
import { IUser, User } from './models'
import helpers from '../../utils/helpers'
import { Chat } from '../chats/models'
import { Message } from '../messages/models'
import { Event } from '../events/models'
import { Request as JoinRequest } from '../requests/models'
import { Reel } from '../reels/models'
import reelControllers from '../reels/controllers'
import { Comment } from '../comments/models'
import { Like } from '../likes/models'
import { View } from '../views/models'
import { SuperLike } from '../super-likes/models'
import { Share } from '../shares/models'
import { Favorite } from '../favorites/models'
import { Blocking } from '../blockings/models'
import { Connection } from '../connections/models'
import { Follower } from '../followers/models'
import { MutualFollow } from '../mutual-follows/models'
import { Notification } from '../notifications/models'
import { Report } from '../reports/models'
import { RewardHash } from '../reward-hashes/models'
import { Score } from '../scores/models'
import { Contact } from '../contacts/models'
import { ContactUs } from '../contact-us/models'
import { Schedule } from '../schedulers/models'
import { Usage } from '../usages/models'
import { Status } from '../statuses/models'

/**
 * Permanently delete a user and all their data from all collections and files (R2).
 * Logs and swallows errors so callers do not need try-catch.
 */
export async function deleteUserAndAllData(userId: Types.ObjectId): Promise<void> {
	await helpers.runInBackground(async () => {
		const user = await User.findById(userId)
		if (!user) {
			throw new Error(`User not found: ${userId}`)
		}

		// 1. Reels: delete each reel and its assets (files, likes, views, comments, etc.); skip user.posts update
		const reels = await Reel.find({ user: userId })
		for (const reel of reels) {
			await reelControllers.deleteReelAndItsAssets(reel, user as IUser, true, true)
		}

		// 2. One-to-one chats: delete chat, messages, message files, chat photo, events, join requests
		const oneToOneChats = await Chat.find({
			'participants.user': userId,
			$or: [{ isGroup: { $ne: true } }, { isGroup: { $exists: false } }]
		}).select('_id event photo').lean()
		for (const chat of oneToOneChats) {
			const chatId = chat._id
			if (chat.event) {
				const event = await Event.findById(chat.event).select('cover').lean()
				if (event?.cover) {
					await helpers.deleteR2File(event.cover)
				}
				await Event.deleteOne({ _id: chat.event })
			}
			const messages = await Message.find({ chat: chatId }).select('files').lean()
			const fileUrls: string[] = []
			for (const m of messages) {
				if (m.files) for (const f of m.files) fileUrls.push(f.url)
			}
			await Promise.allSettled(fileUrls.map(url => helpers.deleteR2File(url)))
			await Message.deleteMany({ chat: chatId })
			if (chat.photo) {
				await helpers.deleteR2File(chat.photo)
			}
			await helpers.deleteR2FilesWithPrefix(`chats/${chatId}`)
			await JoinRequest.deleteMany({ chat: chatId })
			await Chat.deleteOne({ _id: chatId })
		}

		// 3. Group chats: remove this user from participants only
		await Chat.updateMany(
			{ isGroup: true, 'participants.user': userId },
			{ $pull: { participants: { user: userId } } }
		)

		// 4. Events created by this user (e.g. meet-me events); unset event from chats then delete events
		const userEvents = await Event.find({ user: userId }).select('_id cover').lean()
		const eventIds = userEvents.map(e => e._id)
		const eventCoverUrls = userEvents.map(e => e.cover).filter(Boolean) as string[]
		await Promise.allSettled(eventCoverUrls.map(url => helpers.deleteR2File(url)))
		await Event.deleteMany({ user: userId })
		await Chat.updateMany({ event: { $in: eventIds } }, { $unset: { event: 1 } })

		// 5. Requests (join-chat requests by this user)
		await JoinRequest.deleteMany({ user: userId })

		// 6. Connections (from or to this user)
		await Connection.deleteMany({ $or: [{ from: userId }, { to: userId }] })

		// 7. Statuses
		await Status.deleteMany({ user: userId })

		// 8. Blockings (user blocked or was blocked by)
		await Blocking.deleteMany({ $or: [{ user: userId }, { blockedBy: userId }] })

		// 9. Followers
		await Follower.deleteMany({ $or: [{ follower: userId }, { following: userId }] })

		// 10. Mutual follows
		await MutualFollow.deleteMany({ users: userId })

		// 11. Likes, Views, SuperLikes, Shares, Favorites (by this user)
		await Like.deleteMany({ user: userId })
		await View.deleteMany({ user: userId })
		await SuperLike.deleteMany({ user: userId })
		await Share.deleteMany({ user: userId })
		await Favorite.deleteMany({ user: userId })

		// 12. Comments by this user
		await Comment.deleteMany({ user: userId })

		// 13. Notifications (to or from this user)
		await Notification.deleteMany({ $or: [{ user: userId }, { from: userId }] })

		// 14. Reports (reported by or reporting this user)
		await Report.deleteMany({ $or: [{ reportedBy: userId }, { user: userId }] })

		// 15. Reward hashes, scores, contacts, contact-us, deletions, schedules, usages
		await RewardHash.deleteMany({ user: userId })
		await Score.deleteMany({ user: userId })
		await Contact.deleteMany({ user: userId })
		await ContactUs.deleteMany({ user: userId })
		await Schedule.deleteMany({ user: userId })
		await Usage.deleteMany({ user: userId })

		// 16. User profile photo (R2)
		if (user.photo) {
			await helpers.deleteR2File(user.photo)
		}

		// 17. User document
		await user.deleteOne()

		console.log('🗑️ User permanently deleted', user.email, user.name, user.username, userId.toString())
	})
}
