//
//  MIDIPickerViewController.swift
//  DashSmash
//
//  Searches BitMidi for Standard MIDI files, downloads the selected result,
//  parses its note events, and starts a MIDI-synchronized level.
//

import UIKit

final class MIDIPickerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
    private let backButton = UIButton(type: .system)
    private let titleLabel = UILabel()
    private let queryField = UITextField()
    private let searchButton = UIButton(type: .system)
    private let tableView = UITableView(frame: .zero, style: .plain)
    private let statusLabel = UILabel()
    private let activity = UIActivityIndicatorView(style: .medium)

    private let loadingOverlay = UIView()
    private let loadingPanel = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialDark))
    private let loadingTint = UIView()
    private let loadingActivity = UIActivityIndicatorView(style: .large)
    private let loadingLabel = UILabel()

    private var results: [MIDISearchResult] = []
    private var searchTask: Task<Void, Never>?

    // Survives navigation so returning to the picker shows the prior search
    // — the common flow is to try another result from the same query.
    private static var lastQuery: String = ""
    private static var lastResults: [MIDISearchResult] = []
    private static var lastStatus: String?

    override var prefersStatusBarHidden: Bool { true }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask { .allButUpsideDown }

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

    private func restoreLastSearch() {
        let saved = Self.lastQuery
        guard !saved.isEmpty else { return }
        queryField.text = saved
        results = Self.lastResults
        tableView.reloadData()
        if let status = Self.lastStatus {
            statusLabel.text = status
        } else if !results.isEmpty {
            statusLabel.text = nil
        }
    }

    private func setupUI() {
        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)

        titleLabel.text = "MIDI SEARCH"
        titleLabel.textColor = .white
        titleLabel.font = UIFont(name: "AvenirNext-Heavy", size: 22) ?? .boldSystemFont(ofSize: 22)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(titleLabel)

        styleField(queryField, placeholder: "Song and/or artist")
        queryField.delegate = self
        queryField.returnKeyType = .search

        styleSearchButton()

        let searchStack = UIStackView(arrangedSubviews: [queryField, searchButton])
        searchStack.axis = .vertical
        searchStack.spacing = 10
        searchStack.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(searchStack)

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

        statusLabel.text = "Search by song, artist, or both. Results are MIDI files from BitMidi."
        statusLabel.textColor = UIColor.white.withAlphaComponent(0.65)
        statusLabel.font = UIFont(name: "AvenirNext-Medium", size: 14) ?? .systemFont(ofSize: 14)
        statusLabel.textAlignment = .center
        statusLabel.numberOfLines = 0
        statusLabel.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(statusLabel)

        activity.color = .white
        activity.hidesWhenStopped = true
        activity.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(activity)

        setupLoadingOverlay()

        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),

            searchStack.topAnchor.constraint(equalTo: backButton.bottomAnchor, constant: 14),
            searchStack.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 24),
            searchStack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -24),
            queryField.heightAnchor.constraint(equalToConstant: 44),
            searchButton.heightAnchor.constraint(equalToConstant: 48),

            tableView.topAnchor.constraint(equalTo: searchStack.bottomAnchor, constant: 12),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            statusLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            statusLabel.centerYAnchor.constraint(equalTo: tableView.centerYAnchor),
            statusLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32),
            statusLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -32),

            activity.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            activity.topAnchor.constraint(equalTo: statusLabel.bottomAnchor, constant: 12),

            loadingOverlay.topAnchor.constraint(equalTo: tableView.topAnchor),
            loadingOverlay.leadingAnchor.constraint(equalTo: tableView.leadingAnchor),
            loadingOverlay.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
            loadingOverlay.bottomAnchor.constraint(equalTo: tableView.bottomAnchor)
        ])
    }

    private func setupLoadingOverlay() {
        loadingOverlay.backgroundColor = UIColor.black.withAlphaComponent(0.55)
        loadingOverlay.isHidden = true
        loadingOverlay.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(loadingOverlay)

        loadingPanel.layer.cornerRadius = 20
        loadingPanel.layer.masksToBounds = true
        loadingPanel.layer.borderColor = UIColor.white.withAlphaComponent(0.22).cgColor
        loadingPanel.layer.borderWidth = 1
        loadingPanel.translatesAutoresizingMaskIntoConstraints = false
        loadingOverlay.addSubview(loadingPanel)

        loadingTint.backgroundColor = UIColor.systemTeal.withAlphaComponent(0.18)
        loadingTint.translatesAutoresizingMaskIntoConstraints = false
        loadingPanel.contentView.addSubview(loadingTint)

        loadingActivity.color = .white
        loadingActivity.translatesAutoresizingMaskIntoConstraints = false
        loadingPanel.contentView.addSubview(loadingActivity)

        loadingLabel.text = "Loading MIDI…"
        loadingLabel.textColor = .white
        loadingLabel.font = UIFont(name: "AvenirNext-DemiBold", size: 15) ?? .systemFont(ofSize: 15, weight: .semibold)
        loadingLabel.textAlignment = .center
        loadingLabel.translatesAutoresizingMaskIntoConstraints = false
        loadingPanel.contentView.addSubview(loadingLabel)

        NSLayoutConstraint.activate([
            loadingPanel.centerXAnchor.constraint(equalTo: loadingOverlay.centerXAnchor),
            loadingPanel.centerYAnchor.constraint(equalTo: loadingOverlay.centerYAnchor),
            loadingPanel.widthAnchor.constraint(greaterThanOrEqualToConstant: 220),

            loadingTint.topAnchor.constraint(equalTo: loadingPanel.contentView.topAnchor),
            loadingTint.leadingAnchor.constraint(equalTo: loadingPanel.contentView.leadingAnchor),
            loadingTint.trailingAnchor.constraint(equalTo: loadingPanel.contentView.trailingAnchor),
            loadingTint.bottomAnchor.constraint(equalTo: loadingPanel.contentView.bottomAnchor),

            loadingActivity.centerXAnchor.constraint(equalTo: loadingPanel.contentView.centerXAnchor),
            loadingActivity.topAnchor.constraint(equalTo: loadingPanel.contentView.topAnchor, constant: 22),

            loadingLabel.centerXAnchor.constraint(equalTo: loadingPanel.contentView.centerXAnchor),
            loadingLabel.topAnchor.constraint(equalTo: loadingActivity.bottomAnchor, constant: 14),
            loadingLabel.bottomAnchor.constraint(equalTo: loadingPanel.contentView.bottomAnchor, constant: -22),
            loadingLabel.leadingAnchor.constraint(greaterThanOrEqualTo: loadingPanel.contentView.leadingAnchor, constant: 28),
            loadingLabel.trailingAnchor.constraint(lessThanOrEqualTo: loadingPanel.contentView.trailingAnchor, constant: -28)
        ])
    }

    private func showLoadingOverlay() {
        view.bringSubviewToFront(loadingOverlay)
        loadingOverlay.alpha = 0
        loadingOverlay.isHidden = false
        loadingActivity.startAnimating()
        tableView.isUserInteractionEnabled = false
        searchButton.isEnabled = false
        UIView.animate(withDuration: 0.18) { [weak self] in
            self?.loadingOverlay.alpha = 1
        }
    }

    private func hideLoadingOverlay() {
        loadingActivity.stopAnimating()
        tableView.isUserInteractionEnabled = true
        searchButton.isEnabled = true
        UIView.animate(withDuration: 0.18, animations: { [weak self] in
            self?.loadingOverlay.alpha = 0
        }, completion: { [weak self] _ in
            self?.loadingOverlay.isHidden = true
        })
    }

    private func styleField(_ field: UITextField, placeholder: String) {
        field.placeholder = placeholder
        field.attributedPlaceholder = NSAttributedString(
            string: placeholder,
            attributes: [.foregroundColor: UIColor.white.withAlphaComponent(0.35)]
        )
        field.textColor = .white
        field.tintColor = .white
        field.font = UIFont(name: "AvenirNext-Medium", size: 17) ?? .systemFont(ofSize: 17)
        field.backgroundColor = UIColor.white.withAlphaComponent(0.08)
        field.layer.cornerRadius = 10
        field.layer.borderColor = UIColor.white.withAlphaComponent(0.2).cgColor
        field.layer.borderWidth = 1
        field.autocorrectionType = .no
        field.autocapitalizationType = .words
        let pad = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 1))
        field.leftView = pad
        field.leftViewMode = .always
    }

    private func styleSearchButton() {
        searchButton.setTitle("Search MIDI", for: .normal)
        searchButton.titleLabel?.font = UIFont(name: "AvenirNext-Heavy", size: 20) ?? .boldSystemFont(ofSize: 20)
        searchButton.setTitleColor(.black, for: .normal)
        searchButton.backgroundColor = .white
        searchButton.layer.cornerRadius = 12
        searchButton.addTarget(self, action: #selector(searchTapped), for: .touchUpInside)
    }

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

    @objc private func searchTapped() {
        view.endEditing(true)
        runSearch()
    }

    private func runSearch() {
        searchTask?.cancel()
        let query = (queryField.text ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
        guard !query.isEmpty else {
            statusLabel.text = "Enter a song name, artist, or both."
            return
        }
        Self.lastQuery = query

        searchTask = Task { [weak self] in
            guard let self else { return }
            self.activity.startAnimating()
            self.statusLabel.text = nil
            do {
                let found = try await MIDISearchService.shared.search(query: query)
                if Task.isCancelled { return }
                self.results = found
                self.tableView.reloadData()
                let status = found.isEmpty ? "No MIDI results found." : nil
                self.statusLabel.text = status
                Self.lastResults = found
                Self.lastStatus = status
            } catch {
                self.results = []
                self.tableView.reloadData()
                let status = "MIDI search failed:\n\(error.localizedDescription)"
                self.statusLabel.text = status
                Self.lastResults = []
                Self.lastStatus = status
            }
            self.activity.stopAnimating()
        }
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let result = results[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.backgroundColor = .black
        cell.selectionStyle = .gray
        var config = UIListContentConfiguration.cell()
        config.text = result.title
        config.secondaryText = result.pageURL.host ?? result.artistName
        config.textProperties.color = .white
        config.textProperties.font = UIFont(name: "AvenirNext-Bold", size: 16) ?? .boldSystemFont(ofSize: 16)
        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) {
        tableView.deselectRow(at: indexPath, animated: true)
        let result = results[indexPath.row]
        load(result: result)
    }

    private func load(result: MIDISearchResult) {
        statusLabel.text = nil
        searchTask?.cancel()
        showLoadingOverlay()
        searchTask = Task { [weak self] in
            guard let self else { return }
            do {
                let song = try await MIDISearchService.shared.loadSong(from: result)
                if Task.isCancelled {
                    self.hideLoadingOverlay()
                    return
                }
                let level = MIDILevelBuilder.makeLevel(from: song)
                let game = GameViewController(level: level, track: .midi(song))
                self.hideLoadingOverlay()
                self.navigationController?.pushViewController(game, animated: true)
            } catch {
                self.hideLoadingOverlay()
                self.statusLabel.text = "Couldn't load MIDI:\n\(error.localizedDescription)"
            }
        }
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        runSearch()
        return true
    }
}
