import Foundation

// MARK: - Cached Regexes for Title Normalization
private enum TitleNormalizationRegex {
    static let yearWithDash: NSRegularExpression? = try? NSRegularExpression(pattern: #"\s*-\s*\d{4}\s*$"#)
    static let yearInParens: NSRegularExpression? = try? NSRegularExpression(pattern: #"\s*\(\d{4}\)\s*"#)
}

/// Represents a group of VODItems that are the same movie but different versions/qualities
struct MovieGroup: Identifiable, Hashable {
    let id: String  // Uses the primary item's ID
    let normalizedTitle: String
    let versions: [VODItem]

    /// The primary/representative item to display (prefers highest quality)
    var primaryItem: VODItem {
        versions.first ?? versions[0]
    }

    /// Display name (from primary item)
    var name: String {
        primaryItem.name
    }

    /// Whether this group has multiple versions
    var hasMultipleVersions: Bool {
        versions.count > 1
    }

    /// Number of available versions
    var versionCount: Int {
        versions.count
    }

    init(normalizedTitle: String, versions: [VODItem]) {
        self.normalizedTitle = normalizedTitle
        // Sort versions: 4K first, then by name
        self.versions = versions.sorted { v1, v2 in
            let is4K1 = v1.name.lowercased().contains("4k")
            let is4K2 = v2.name.lowercased().contains("4k")
            if is4K1 != is4K2 {
                return is4K1  // 4K versions first
            }
            return v1.name < v2.name
        }
        self.id = self.versions.first?.id ?? UUID().uuidString
    }

    // MARK: - Hashable
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }

    static func == (lhs: MovieGroup, rhs: MovieGroup) -> Bool {
        lhs.id == rhs.id
    }
}

// MARK: - Grouping Extension

extension Array where Element == VODItem {
    /// Groups VOD items by normalized title, creating MovieGroups for deduplication
    /// Uses parallel processing for performance with large datasets
    func groupedByTitle() -> [MovieGroup] {
        guard !isEmpty else { return [] }

        let items = self
        let count = items.count

        // Step 1: Compute normalized titles in parallel
        var normalizedTitles = [String](repeating: "", count: count)
        let chunkSize = Swift.max(1000, count / 8)  // Process in chunks

        DispatchQueue.concurrentPerform(iterations: (count + chunkSize - 1) / chunkSize) { chunkIndex in
            let start = chunkIndex * chunkSize
            let end = Swift.min(start + chunkSize, count)
            for i in start..<end {
                normalizedTitles[i] = items[i].normalizedTitleForGrouping
            }
        }

        // Step 2: Group items by normalized title (single-threaded for thread safety)
        var groups: [String: [VODItem]] = [:]
        groups.reserveCapacity(count / 2)  // Estimate ~2 versions per movie avg

        for i in 0..<count {
            let normalized = normalizedTitles[i]
            groups[normalized, default: []].append(items[i])
        }

        // Step 3: Convert to MovieGroup array in parallel
        let groupKeys: [String] = groups.keys.map { $0 }
        var movieGroups = [MovieGroup?](repeating: nil, count: groupKeys.count)
        let groupChunkSize = Swift.max(500, groupKeys.count / 8)

        DispatchQueue.concurrentPerform(iterations: (groupKeys.count + groupChunkSize - 1) / groupChunkSize) { chunkIndex in
            let start = chunkIndex * groupChunkSize
            let end = Swift.min(start + groupChunkSize, groupKeys.count)
            for i in start..<end {
                let key = groupKeys[i]
                if let versions = groups[key] {
                    movieGroups[i] = MovieGroup(normalizedTitle: key, versions: versions)
                }
            }
        }

        // Step 4: Compact and sort by most recent year first
        var result = movieGroups.compactMap { $0 }

        // Pre-compute years for sorting in parallel
        var years = [Int](repeating: 0, count: result.count)
        let sortChunkSize = Swift.max(500, result.count / 8)

        DispatchQueue.concurrentPerform(iterations: (result.count + sortChunkSize - 1) / sortChunkSize) { chunkIndex in
            let start = chunkIndex * sortChunkSize
            let end = Swift.min(start + sortChunkSize, result.count)
            for i in start..<end {
                years[i] = result[i].primaryItem.releaseYear ?? 0
            }
        }

        // Create indexed array for sorting
        var indexed = result.enumerated().map { ($0.offset, $0.element) }
        indexed.sort { pair1, pair2 in
            let year1 = years[pair1.0]
            let year2 = years[pair2.0]
            if year1 != year2 {
                return year1 > year2
            }
            return pair1.1.name < pair2.1.name
        }

        return indexed.map { $0.1 }
    }
}

// MARK: - VODItem Extension for Grouping

extension VODItem {
    /// Normalized title for grouping (removes quality indicators, years, etc.)
    var normalizedTitleForGrouping: String {
        var normalized = name.lowercased()

        // Remove quality prefixes like "4K: " or "4K - "
        let qualityPrefixes = ["4k: ", "4k - ", "4k:", "hd: ", "hd - ", "hd:"]
        for prefix in qualityPrefixes {
            if normalized.hasPrefix(prefix) {
                normalized = String(normalized.dropFirst(prefix.count))
            }
        }

        // Remove year with dash at end, e.g., "- 2024" (using cached regex)
        if let regex = TitleNormalizationRegex.yearWithDash {
            let range = NSRange(normalized.startIndex..., in: normalized)
            normalized = regex.stringByReplacingMatches(in: normalized, range: range, withTemplate: "")
        }

        // Remove year in parentheses, e.g., "(2024)" (using cached regex)
        if let regex = TitleNormalizationRegex.yearInParens {
            let range = NSRange(normalized.startIndex..., in: normalized)
            normalized = regex.stringByReplacingMatches(in: normalized, range: range, withTemplate: " ")
        }

        // Remove quality suffixes
        let qualitySuffixes = [" 4k", " uhd", " hd", " 1080p", " 720p", " 480p", " bluray", " blu-ray", " webrip", " web-dl", " hdrip", " dvdrip", " brrip"]
        for suffix in qualitySuffixes {
            if normalized.hasSuffix(suffix) {
                normalized = String(normalized.dropLast(suffix.count))
            }
        }

        // Remove punctuation and normalize spaces
        normalized = normalized.components(separatedBy: CharacterSet.alphanumerics.union(.whitespaces).inverted).joined()
        normalized = normalized.components(separatedBy: .whitespaces)
            .filter { !$0.isEmpty }
            .joined(separator: " ")
            .trimmingCharacters(in: .whitespaces)

        return normalized
    }

    /// Quality label for display (e.g., "4K", "HD", "Standard")
    var qualityLabel: String {
        let lowercaseName = name.lowercased()
        if lowercaseName.contains("4k") {
            return "4K"
        } else if lowercaseName.contains("1080p") || lowercaseName.contains("bluray") || lowercaseName.contains("blu-ray") {
            return "1080p"
        } else if lowercaseName.contains("720p") || lowercaseName.contains("hd") {
            return "720p"
        } else if lowercaseName.contains("480p") {
            return "480p"
        }
        return "Standard"
    }
}
