//
//  SavedLevelsViewController.swift
//  DashSmash
//
//  Lists saved levels and lets the player replay or delete them.
//

import UIKit
import MediaPlayer

final class SavedLevelsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    private let tableView = UITableView(frame: .zero, style: .plain)
    private let emptyLabel = UILabel()
    private let backButton = UIButton(type: .system)
    private let titleLabel = UILabel()

    private var levels: [Level] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        setupUI()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        levels = SavedLevelsStore.shared.loadAll()
        tableView.reloadData()
        updateEmptyState()
    }

    override var prefersStatusBarHidden: Bool { true }

    private func setupUI() {
        titleLabel.text = "SAVED LEVELS"
        titleLabel.textColor = .white
        titleLabel.font = UIFont(name: "AvenirNext-Heavy", size: 22) ?? .boldSystemFont(ofSize: 22)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(titleLabel)

        backButton.setTitle("← Back", for: .normal)
        backButton.titleLabel?.font = UIFont(name: "AvenirNext-Medium", size: 17) ?? .systemFont(ofSize: 17)
        backButton.setTitleColor(.white, for: .normal)
        backButton.addTarget(self, action: #selector(backTapped), for: .touchUpInside)
        backButton.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(backButton)

        tableView.backgroundColor = .black
        tableView.separatorColor = UIColor.white.withAlphaComponent(0.15)
        tableView.dataSource = self
        tableView.delegate = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        view.addSubview(tableView)

        emptyLabel.text = "No saved levels yet.\nPlay a song and save the level when you finish."
        emptyLabel.numberOfLines = 0
        emptyLabel.textColor = UIColor.white.withAlphaComponent(0.6)
        emptyLabel.textAlignment = .center
        emptyLabel.font = UIFont(name: "AvenirNext-Medium", size: 16) ?? .systemFont(ofSize: 16)
        emptyLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(emptyLabel)

        NSLayoutConstraint.activate([
            backButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            backButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),

            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            titleLabel.centerYAnchor.constraint(equalTo: backButton.centerYAnchor),

            tableView.topAnchor.constraint(equalTo: backButton.bottomAnchor, constant: 16),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            emptyLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            emptyLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            emptyLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32),
            emptyLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32)
        ])
    }

    private func updateEmptyState() {
        emptyLabel.isHidden = !levels.isEmpty
        tableView.isHidden = levels.isEmpty
    }

    @objc private func backTapped() {
        navigationController?.popViewController(animated: true)
    }

    // MARK: - Table view

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        levels.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let level = levels[indexPath.row]
        cell.backgroundColor = .black
        // Show an immediate down-state when the cell is tapped — replaying a
        // saved level can spin up Apple Music / library lookups before the
        // game pushes, so the player needs visible feedback that the tap
        // landed.
        cell.selectionStyle = .default
        let selectedBackground = UIView()
        selectedBackground.backgroundColor = UIColor.white.withAlphaComponent(0.18)
        cell.selectedBackgroundView = selectedBackground
        var config = UIListContentConfiguration.cell()
        config.text = level.displayTitle
        config.secondaryText = String(
            format: "%.0f BPM • %d sections • %@",
            level.bpm, level.sections.count,
            level.style.rawValue
        )
        config.textProperties.color = .white
        config.textProperties.font = UIFont(name: "AvenirNext-Bold", size: 17) ?? .boldSystemFont(ofSize: 17)
        config.secondaryTextProperties.color = UIColor.white.withAlphaComponent(0.6)
        config.secondaryTextProperties.font = UIFont(name: "AvenirNext-Medium", size: 13) ?? .systemFont(ofSize: 13)
        cell.contentConfiguration = config
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let level = levels[indexPath.row]
        // Keep the row highlighted while replay() does its async work — the
        // cell will be deselected naturally when this view disappears as the
        // game pushes on top.
        replay(level: level)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let indexPath = tableView.indexPathForSelectedRow {
            tableView.deselectRow(at: indexPath, animated: animated)
        }
    }

    private func replay(level: Level) {
        guard let sourceID = level.trackSourceID else {
            // Synth-only level.
            let game = GameViewController(level: level)
            navigationController?.pushViewController(game, animated: true)
            return
        }
        if sourceID.hasPrefix("am:") {
            let songID = String(sourceID.dropFirst(3))
            Task { [weak self] in
                guard let self else { return }
                _ = await AppleMusicCoordinator.shared.authorize()
                if let song = try? await AppleMusicCoordinator.shared.fetchSong(id: songID) {
                    try? await AppleMusicCoordinator.shared.play(song: song)
                    let game = GameViewController(level: level, track: .appleMusicCatalog(song))
                    self.navigationController?.pushViewController(game, animated: true)
                } else {
                    // Apple Music unavailable — fall back to synth.
                    let game = GameViewController(level: level)
                    self.navigationController?.pushViewController(game, animated: true)
                }
            }
        } else if sourceID.hasPrefix("midi:") {
            // Reconstruct the MIDISong from the saved `.mid` bytes so playback
            // is offline-fast and identical to the original session.
            guard let data = SavedLevelsStore.shared.midiData(for: level),
                  let parsed = try? MIDIFileParser.parse(data) else {
                // No sidecar (older save, manual deletion, or a corrupt file)
                // — fall back to the synth so the level still plays.
                let game = GameViewController(level: level)
                navigationController?.pushViewController(game, animated: true)
                return
            }
            let pageURL = URL(string: String(sourceID.dropFirst("midi:".count))) ?? URL(string: "midi:saved")!
            let song = MIDISong(
                title: level.songName,
                artistName: level.bandName,
                sourcePageURL: pageURL,
                downloadURL: pageURL,
                data: data,
                parsedFile: parsed
            )
            let game = GameViewController(level: level, track: .midi(song))
            navigationController?.pushViewController(game, animated: true)
        } else if sourceID.hasPrefix("lib:") {
            let raw = String(sourceID.dropFirst(4))
            guard let persistentID = UInt64(raw) else {
                let game = GameViewController(level: level)
                navigationController?.pushViewController(game, animated: true)
                return
            }
            if let item = lookupLibraryItem(persistentID: persistentID) {
                let player = MPMusicPlayerController.applicationMusicPlayer
                player.setQueue(with: MPMediaItemCollection(items: [item]))
                player.play()
                let game = GameViewController(level: level, track: .library(item))
                navigationController?.pushViewController(game, animated: true)
            } else {
                // Item no longer in library — fall back to synth.
                let game = GameViewController(level: level)
                navigationController?.pushViewController(game, animated: true)
            }
        } else {
            let game = GameViewController(level: level)
            navigationController?.pushViewController(game, animated: true)
        }
    }

    private func lookupLibraryItem(persistentID: UInt64) -> MPMediaItem? {
        let query = MPMediaQuery.songs()
        let predicate = MPMediaPropertyPredicate(
            value: NSNumber(value: persistentID),
            forProperty: MPMediaItemPropertyPersistentID
        )
        query.addFilterPredicate(predicate)
        return query.items?.first
    }

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        guard editingStyle == .delete else { return }
        deleteLevel(at: indexPath)
    }

    /// Modern swipe-actions API — gives the player a visible "Delete" pill
    /// when they swipe left, instead of relying on the legacy half-swipe
    /// behavior that some users miss.
    func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let action = UIContextualAction(style: .destructive, title: "Delete") { [weak self] _, _, completion in
            self?.deleteLevel(at: indexPath)
            completion(true)
        }
        action.backgroundColor = .systemRed
        return UISwipeActionsConfiguration(actions: [action])
    }

    private func deleteLevel(at indexPath: IndexPath) {
        guard indexPath.row < levels.count else { return }
        let level = levels[indexPath.row]
        SavedLevelsStore.shared.delete(level)
        levels.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .automatic)
        updateEmptyState()
    }
}
