import UIKit
import ImageIO

class GIFPlayerView: UIView {
	private var imageView: UIImageView!
	private var displayLink: CADisplayLink?
	private var imageSource: CGImageSource?
	private var frameCount: Int = 0
	private var currentFrameIndex: Int = 0
	private var frameDurations: [TimeInterval] = []
	private var totalDuration: TimeInterval = 0
	private var currentTime: TimeInterval = 0
	private var previousTimestamp: TimeInterval = 0
	
	// Default configuration
	private var loopCount: Int = 0 // 0 means loop forever
	private var currentLoopCount: Int = 0
	
	// Public properties
	var isPlaying: Bool = false
	
	override init(frame: CGRect) {
		super.init(frame: frame)
		commonInit()
	}
	
	required init?(coder: NSCoder) {
		super.init(coder: coder)
		commonInit()
	}
	
	deinit {
		stopAnimating()
	}
	
	private func commonInit() {
		imageView = UIImageView()
		imageView.contentMode = .scaleAspectFit
		imageView.clipsToBounds = true
		addSubview(imageView)
		
		imageView.translatesAutoresizingMaskIntoConstraints = false
		NSLayoutConstraint.activate([
			imageView.topAnchor.constraint(equalTo: topAnchor),
			imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
			imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
			imageView.bottomAnchor.constraint(equalTo: bottomAnchor)
		])
	}
	
	// MARK: - Public Methods
	
	func loadGIF(from data: Data) {
		stopAnimating()
		
		guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return }
		imageSource = source
		
		// Get frame count
		frameCount = CGImageSourceGetCount(source)
		guard frameCount > 0 else { return }
		
		// Calculate frame durations
		frameDurations.removeAll()
		totalDuration = 0
		
		for i in 0..<frameCount {
			let duration = frameDurationAtIndex(i)
			frameDurations.append(duration)
			totalDuration += duration
		}
		
		// Reset state
		currentFrameIndex = 0
		currentTime = 0
		
		// Display first frame
		if let image = imageAtIndex(0) {
			imageView.image = image
		}
	}
	
	func startAnimating() {
		guard !isPlaying, frameCount > 1 else { return }
		
		isPlaying = true
		previousTimestamp = CACurrentMediaTime()
		
		displayLink = CADisplayLink(target: self, selector: #selector(updateFrame))
		displayLink?.add(to: .main, forMode: .common)
	}
	
	func stopAnimating() {
		isPlaying = false
		displayLink?.invalidate()
		displayLink = nil
	}
	
	func loadGIF(from url: URL, completion: @escaping (Bool) -> Void) {
		URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
			guard let self = self, let data = data, error == nil else {
				DispatchQueue.main.async {
					completion(false)
				}
				return
			}
			
			DispatchQueue.main.async {
				self.loadGIF(from: data)
				completion(true)
			}
		}.resume()
	}
	
	// MARK: - Private Methods
	
	@objc private func updateFrame(displayLink: CADisplayLink) {
		let timestamp = CACurrentMediaTime()
		let elapsed = timestamp - previousTimestamp
		previousTimestamp = timestamp
		
		currentTime += elapsed
		
		// Check if we need to show the next frame
		while currentTime >= frameDurations[currentFrameIndex], frameCount > 0 {
			currentTime -= frameDurations[currentFrameIndex]
			currentFrameIndex = (currentFrameIndex + 1) % frameCount
			
			// Handle loop count
			if currentFrameIndex == 0 && loopCount > 0 {
				currentLoopCount += 1
				if currentLoopCount >= loopCount {
					stopAnimating()
					break
				}
			}
			
			// Update the image
			if let image = imageAtIndex(currentFrameIndex) {
				imageView.image = image
			}
		}
	}
	
	private func imageAtIndex(_ index: Int) -> UIImage? {
		guard let source = imageSource, index < frameCount,
			  let cgImage = CGImageSourceCreateImageAtIndex(source, index, nil) else {
			return nil
		}
		
		return UIImage(cgImage: cgImage)
	}
	
	private func frameDurationAtIndex(_ index: Int) -> TimeInterval {
		guard let source = imageSource, index < frameCount else {
			return 0.1 // Default duration
		}
		
		// Get frame properties
		guard let properties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) as? [String: Any],
			  let gifProperties = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any] else {
			return 0.1 // Default duration
		}
		
		// Get delay time
		var delayTime: TimeInterval = 0.1 // Default duration
		
		if let unclampedDelay = gifProperties[kCGImagePropertyGIFUnclampedDelayTime as String] as? TimeInterval,
		   unclampedDelay > 0 {
			delayTime = unclampedDelay
		} else if let delay = gifProperties[kCGImagePropertyGIFDelayTime as String] as? TimeInterval,
				  delay > 0 {
			delayTime = delay
		}
		
		// Clamp to minimum delay (ensures reasonable frame rate)
		return max(delayTime, 0.02)
	}
}
