import UIKit

/// UIView wrapper that drives a `GameOfLifeLayer` with a repeating Timer.
///
/// Lifecycle:
/// - Animation starts when the view moves to a window.
/// - Animation pauses when the view leaves its window (battery-safe).
/// - Timer fires every 160ms.
final class GameOfLifeUIView: UIView {

    // MARK: - Configuration

    /// Tick interval in seconds.
    static let tickInterval: TimeInterval = 0.16

    /// Grid dimension.
    let gridSize: Int

    /// Fill color for live cells.
    var tintUIColor: UIColor = .label {
        didSet { golLayer.tintCGColor = tintUIColor.cgColor }
    }

    // MARK: - State

    private let golLayer: GameOfLifeLayer
    nonisolated(unsafe) private var timer: Timer?

    // MARK: - Init

    init(gridSize: Int = 6) {
        self.gridSize = gridSize
        self.golLayer = GameOfLifeLayer(gridSize: gridSize)
        super.init(frame: .zero)
        layer.addSublayer(golLayer)
        isOpaque = false
        backgroundColor = .clear
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError("Not supported") }

    deinit {
        timer?.invalidate()
        timer = nil
    }

    // MARK: - Layout

    override func layoutSubviews() {
        super.layoutSubviews()
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        golLayer.frame = bounds
        golLayer.contentsScale = traitCollection.displayScale
        CATransaction.commit()
    }

    override var intrinsicContentSize: CGSize {
        CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
    }

    // MARK: - Window Lifecycle

    override func didMoveToWindow() {
        super.didMoveToWindow()
        if window != nil {
            startAnimation()
        } else {
            stopAnimation()
        }
    }

    // MARK: - Animation

    private func startAnimation() {
        guard timer == nil else { return }
        timer = Timer.scheduledTimer(
            timeInterval: Self.tickInterval,
            target: self,
            selector: #selector(handleTimerTick),
            userInfo: nil,
            repeats: true
        )
    }

    private func stopAnimation() {
        timer?.invalidate()
        timer = nil
    }

    @objc private func handleTimerTick() {
        timerFired()
    }

    private func timerFired() {
        golLayer.tick()
        golLayer.setNeedsDisplay()
    }
}
