import UIKit

struct MobileProgressBarInfoConfiguration {
    var title: String
    var info: String
    var currentTime: String
    var totalTime: String
    var progress: CGFloat
    var showsTitle: Bool
    var showsInfo: Bool
    var showsTime: Bool
    var showsProgressBar: Bool

    init(
        title: String = "Title here",
        info: String = "Info Text here",
        currentTime: String = "47:38",
        totalTime: String = "1:52:32",
        progress: CGFloat = 0.3846,
        showsTitle: Bool = true,
        showsInfo: Bool = true,
        showsTime: Bool = true,
        showsProgressBar: Bool = true
    ) {
        self.title = title
        self.info = info
        self.currentTime = currentTime
        self.totalTime = totalTime
        self.progress = progress
        self.showsTitle = showsTitle
        self.showsInfo = showsInfo
        self.showsTime = showsTime
        self.showsProgressBar = showsProgressBar
    }
}

final class MobileProgressBarInfoView: UIView {
    private let gradientLayer = CAGradientLayer()
    private let titleLabel = UILabel()
    private let timeLabel = UILabel()
    private let progressTrackView = UIView()
    private let progressFillView = UIView()
    private let progressThumbView = UIView()
    private var progressWidthConstraint: NSLayoutConstraint?
    private var progressThumbCenterXConstraint: NSLayoutConstraint?
    private var normalizedProgress: CGFloat = 0
    private var scrubbingStartProgress: CGFloat = 0

    var onScrubbingBegan: (() -> Void)?
    var onScrubbingChanged: ((CGFloat) -> Void)?
    var onScrubbingEnded: ((CGFloat) -> Void)?

    var configuration = MobileProgressBarInfoConfiguration() {
        didSet {
            applyConfiguration()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        configureView()
        configureHierarchy()
        applyConfiguration()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        configureView()
        configureHierarchy()
        applyConfiguration()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
        updateProgressViews()
    }

    private func configureView() {
        isOpaque = false

        gradientLayer.colors = [
            UIColor(red: 0.05, green: 0.06, blue: 0.08, alpha: 0.0).cgColor,
            UIColor(red: 0.05, green: 0.06, blue: 0.08, alpha: 0.9).cgColor
        ]
        gradientLayer.locations = [0, 0.8037]
        layer.insertSublayer(gradientLayer, at: 0)

        titleLabel.font = UIFont(name: "HelveticaNeue", size: 20) ?? .systemFont(ofSize: 20, weight: .regular)
        titleLabel.textColor = .white
        titleLabel.numberOfLines = 1
        titleLabel.textAlignment = .left
        titleLabel.lineBreakMode = .byTruncatingTail
        titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        timeLabel.font = UIFont(name: "HelveticaNeue-Light", size: 14) ?? .systemFont(ofSize: 14, weight: .light)
        timeLabel.textColor = .white
        timeLabel.numberOfLines = 1
        timeLabel.textAlignment = .right
        timeLabel.lineBreakMode = .byTruncatingTail
        timeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)

        progressTrackView.backgroundColor = UIColor(white: 0.85, alpha: 0.4)
        progressTrackView.layer.cornerRadius = 1
        progressTrackView.clipsToBounds = true

        progressFillView.backgroundColor = .white
        progressFillView.layer.cornerRadius = 1
        progressFillView.clipsToBounds = true

        progressThumbView.backgroundColor = .white
        progressThumbView.layer.cornerRadius = 6
        progressThumbView.isHidden = true

        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleProgressPan(_:)))
        addGestureRecognizer(panGesture)
    }

    private func configureHierarchy() {
        [titleLabel, timeLabel, progressTrackView, progressFillView, progressThumbView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
        }

        addSubview(titleLabel)
        addSubview(timeLabel)
        addSubview(progressTrackView)
        progressTrackView.addSubview(progressFillView)
        addSubview(progressThumbView)
        progressWidthConstraint = progressFillView.widthAnchor.constraint(equalToConstant: 0)
        progressThumbCenterXConstraint = progressThumbView.centerXAnchor.constraint(equalTo: progressTrackView.leadingAnchor)

        NSLayoutConstraint.activate([
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -145),
            titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -34),
            titleLabel.heightAnchor.constraint(equalToConstant: 24),

            timeLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32),
            timeLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -36),
            timeLabel.widthAnchor.constraint(equalToConstant: 120),
            timeLabel.heightAnchor.constraint(equalToConstant: 18),

            progressTrackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
            progressTrackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32),
            progressTrackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -24),
            progressTrackView.heightAnchor.constraint(equalToConstant: 2),

            progressFillView.leadingAnchor.constraint(equalTo: progressTrackView.leadingAnchor),
            progressFillView.topAnchor.constraint(equalTo: progressTrackView.topAnchor),
            progressFillView.bottomAnchor.constraint(equalTo: progressTrackView.bottomAnchor),
            progressWidthConstraint!,

            progressThumbView.widthAnchor.constraint(equalToConstant: 12),
            progressThumbView.heightAnchor.constraint(equalToConstant: 12),
            progressThumbView.centerYAnchor.constraint(equalTo: progressTrackView.centerYAnchor),
            progressThumbCenterXConstraint!
        ])
    }

    private func applyConfiguration() {
        titleLabel.text = configuration.title
        timeLabel.text = "\(configuration.currentTime) / \(configuration.totalTime)"

        titleLabel.isHidden = !configuration.showsTitle
        timeLabel.isHidden = !configuration.showsTime
        progressTrackView.isHidden = !configuration.showsProgressBar

        normalizedProgress = min(max(configuration.progress, 0), 1)
        updateProgressViews()
        setNeedsLayout()
    }

    func showScrubbingProgress(_ progress: CGFloat, currentTime: String, totalTime: String) {
        normalizedProgress = min(max(progress, 0), 1)
        timeLabel.text = "\(currentTime) / \(totalTime)"
        progressThumbView.isHidden = false
        updateProgressViews()
    }

    func hideScrubbingIndicator() {
        progressThumbView.isHidden = true
    }

    private func updateProgressViews() {
        let width = progressTrackView.bounds.width
        progressWidthConstraint?.constant = width * normalizedProgress
        progressThumbCenterXConstraint?.constant = width * normalizedProgress
    }

    private func progress(for translation: CGPoint) -> CGFloat {
        let trackWidth = progressTrackView.bounds.width
        guard trackWidth > 0 else {
            return normalizedProgress
        }

        return min(max(scrubbingStartProgress + translation.x / trackWidth, 0), 1)
    }

    @objc private func handleProgressPan(_ gesture: UIPanGestureRecognizer) {
        guard configuration.showsProgressBar else {
            return
        }

        let scrubbedProgress = progress(for: gesture.translation(in: self))

        switch gesture.state {
        case .began:
            scrubbingStartProgress = normalizedProgress
            progressThumbView.isHidden = false
            showScrubbingProgress(scrubbingStartProgress, currentTime: configuration.currentTime, totalTime: configuration.totalTime)
            onScrubbingBegan?()
            onScrubbingChanged?(scrubbingStartProgress)
        case .changed:
            onScrubbingChanged?(scrubbedProgress)
        case .ended, .cancelled, .failed:
            onScrubbingEnded?(scrubbedProgress)
        default:
            break
        }
    }
}
