//
//  CityMoonCell.swift
//  1Weather
//
//  Created by Dmitry Stepanets on 26.02.2021.
//

import UIKit

class CityMoonCell: UITableViewCell {
    //Private
    private let kCircleInset:CGFloat = 55
    private let headingLabel = UILabel()
    private let headingButton = ArrowButton()
    private let container = UIView()
    private let infoLabel = UILabel()
    private let baseLine = UIView()
    private let moonriseImageView = UIImageView()
    private let moonriseTimeLabel = UILabel()
    private let moonsetImageView = UIImageView()
    private let moonsetTimeLabel = UILabel()
    private let circleGradientLayer = CAGradientLayer()
    private let moonImageView = UIImageView()
    private let moonTypeImageView = UIImageView()
    private let moonTypeLabel = UILabel()
    private var moonProgress:CGFloat = 0.0
    
    //Computed
    private static let dateFormatter: DateFormatter = {
       let fmt = DateFormatter()
        fmt.dateFormat = "h:mm a"
        return fmt
    }()
    private static let nowDateFormatter:DateFormatter = {
        let fmt = DateFormatter()
        fmt.dateFormat = "yyyy-MM-dd h:mm a"
        return fmt
    }()
    
    //MARK:- Cell life cycle
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        prepareCell()
        prepareHeading()
        prepareContainer()
        prepareInfoLabel()
        prepareMoonViews()
        prepareMoonCirle()
        updateUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let center = CGPoint(x: baseLine.frame.origin.x + baseLine.bounds.width / 2, y: baseLine.frame.origin.y)
        let radius = center.x - kCircleInset
        
        //Gradient
        circleGradientLayer.frame = .init(x: kCircleInset - 4,
                                          y: center.y - radius - 4,
                                          width: (radius * 2) + 8,
                                          height: radius + 4)
        
        let circlePath = UIBezierPath(arcCenter: .init(x: circleGradientLayer.frame.width / 2,
                                                       y: circleGradientLayer.frame.height),
                                      radius: (circleGradientLayer.frame.width / 2) - 4,
                                      startAngle: 0,
                                      endAngle: .pi,
                                      clockwise: false)
        
        let mask = CAShapeLayer()
        mask.fillRule = .evenOdd
        mask.fillColor = UIColor.clear.cgColor
        mask.strokeColor = UIColor.black.cgColor
        mask.lineWidth = 2
        mask.path = circlePath.cgPath
        circleGradientLayer.mask = mask
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        updateUI()
    }
    
    //Private
    @objc private func handleHeadingButton() {
        
    }
    
    private func moonPath(progress:CGFloat) -> UIBezierPath {
        var pathProgress = max(0.04, progress)
        pathProgress = min(0.96, pathProgress)
        
        let start:CGFloat = -.pi
        let end:CGFloat = 0
        let percent = (start - end) * pathProgress
        let center = CGPoint(x: baseLine.frame.origin.x + baseLine.bounds.width / 2, y: baseLine.frame.origin.y)
        let radius = center.x - kCircleInset
        
        let path = UIBezierPath(arcCenter: center,
                                radius: radius,
                                startAngle: start,
                                endAngle: start - percent,
                                clockwise: true)
        return path
    }
    
    private func updateUI() {
        switch interfaceStyle {
        case .light:
            headingLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
            container.backgroundColor = UIColor(hex: 0xECEEF6)
            infoLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
            moonTypeLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
            moonriseTimeLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
            moonsetTimeLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
        case .dark:
            headingLabel.textColor = ThemeManager.currentTheme.primaryTextColor
            container.backgroundColor = ThemeManager.currentTheme.containerBackgroundColor
            infoLabel.textColor = ThemeManager.currentTheme.primaryTextColor
            moonTypeLabel.textColor = ThemeManager.currentTheme.primaryTextColor
            moonriseTimeLabel.textColor = ThemeManager.currentTheme.primaryTextColor
            moonsetTimeLabel.textColor = ThemeManager.currentTheme.primaryTextColor
        }
    }
    
    //Public
    public func configure(with location:Location) {
        CityMoonCell.dateFormatter.timeZone = location.today?.timeZone
        CityMoonCell.nowDateFormatter.timeZone = location.today?.timeZone
        moonTypeLabel.text = location.today?.moonPhase?.localized
        
        guard
            let moonrise = location.today?.moonrise,
            let moonset = location.today?.moonset
        else {
            return
        }
        
        moonriseTimeLabel.text = CityMoonCell.dateFormatter.string(from: moonrise)
        moonsetTimeLabel.text = CityMoonCell.dateFormatter.string(from: moonset)
        let moonTimePeriod = moonset.timeIntervalSince1970 - moonrise.timeIntervalSince1970
        let nowString = CityMoonCell.nowDateFormatter.string(from: Date())
        let nowDate = CityMoonCell.nowDateFormatter.date(from: nowString) ?? Date()
        self.moonProgress = CGFloat((nowDate.timeIntervalSince1970 - moonrise.timeIntervalSince1970) / moonTimePeriod)
    }
    
    public func updateMoonPosition() {
        contentView.layoutIfNeeded()
        
        moonImageView.layer.removeAnimation(forKey: "moon.position")
        moonImageView.frame.origin = .init(x: kCircleInset - moonImageView.frame.width / 2,
                                           y: baseLine.frame.origin.y - moonImageView.frame.height)
        
        let animation = CAKeyframeAnimation(keyPath: "position")
        animation.path = self.moonPath(progress: moonProgress).cgPath
        animation.calculationMode = .paced
        animation.duration = 1.3
        animation.rotationMode = .rotateAuto
        animation.isRemovedOnCompletion = false
        animation.fillMode = .forwards
        moonImageView.layer.add(animation, forKey: "moon.position")
    }
}

//MARK:- Prepare
private extension CityMoonCell {
    func prepareCell() {
        selectionStyle = .none
        contentView.backgroundColor = ThemeManager.currentTheme.baseBackgroundColor
    }
    
    func prepareHeading() {
        //Label
        headingLabel.font = AppFont.SFPro.bold(size: 16)
        headingLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
        headingLabel.text = "moon.title".localized().uppercased()
        contentView.addSubview(headingLabel)
        
        headingLabel.snp.makeConstraints { (make) in
            make.left.equalToSuperview().inset(18)
            make.top.equalToSuperview().inset(15)
        }
        
        //Arrow button
        headingButton.addTarget(self, action: #selector(handleHeadingButton), for: .touchUpInside)
        contentView.addSubview(headingButton)
        
        headingButton.snp.makeConstraints { (make) in
            make.width.height.equalTo(30)
            make.right.equalToSuperview().inset(18)
            make.centerY.equalTo(headingLabel)
        }
    }
    
    func prepareContainer() {
        container.layer.cornerRadius = 12
        contentView.addSubview(container)
        
        container.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview().inset(18)
            make.top.equalTo(headingLabel.snp.bottom).offset(18)
            make.bottom.equalToSuperview().inset(15)
            make.height.equalTo(290)
        }
    }
    
    func prepareInfoLabel() {
        infoLabel.numberOfLines = 0
        infoLabel.lineBreakMode = .byWordWrapping
        infoLabel.text = "Tides are higher than usual due to new moon"
        infoLabel.font = AppFont.SFPro.regular(size: 16)
        container.addSubview(infoLabel)
        
        infoLabel.snp.makeConstraints { (make) in
            make.left.top.right.equalToSuperview().inset(18)
        }
    }
    
    func prepareMoonViews() {
        //Base line
        baseLine.backgroundColor = UIColor(hex: 0xc2c9d6)
        baseLine.alpha = 0.47
        container.addSubview(baseLine)
        
        baseLine.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview().inset(2)
            make.height.equalTo(2)
            make.bottom.equalToSuperview().inset(52)
        }
        
        //Up arrow
        moonriseImageView.contentMode = .scaleAspectFit
        moonriseImageView.image = UIImage(named: "moon_up_arrow")
        moonriseImageView.tintColor = UIColor(hex: 0x1f67f3)
        container.addSubview(moonriseImageView)
        
        moonriseImageView.snp.makeConstraints { (make) in
            make.left.equalToSuperview().inset(22)
            make.bottom.equalTo(baseLine.snp.top).offset(-20)
        }
        
        //Down arrow
        moonsetImageView.contentMode = .scaleAspectFit
        moonsetImageView.image = UIImage(named: "moon_down_arrow")
        moonsetImageView.tintColor = UIColor(hex: 0x1f67f3)
        container.addSubview(moonsetImageView)
        
        moonsetImageView.snp.makeConstraints { (make) in
            make.right.equalToSuperview().inset(22)
            make.bottom.equalTo(baseLine.snp.top).offset(-20)
        }
        
        //Type
        moonTypeImageView.contentMode = .scaleAspectFit
        moonTypeImageView.image = UIImage(named: "moon_waxingGibbous")
        container.addSubview(moonTypeImageView)
        
        moonTypeImageView.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.bottom.equalTo(baseLine.snp.top).offset(-56)
            make.width.height.equalTo(30)
        }
        
        moonTypeLabel.font = AppFont.SFPro.regular(size: 14)
        moonTypeLabel.text = "moon.phase.waxingGibbous".localized()
        container.addSubview(moonTypeLabel)
        
        moonTypeLabel.snp.makeConstraints { (make) in
            make.centerX.equalToSuperview()
            make.top.equalTo(moonTypeImageView.snp.bottom).offset(17)
        }
        
        //Times
        moonriseTimeLabel.font = AppFont.SFPro.bold(size: 14)
        moonriseTimeLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
        moonriseTimeLabel.textAlignment = .left
        container.addSubview(moonriseTimeLabel)
        
        moonriseTimeLabel.snp.makeConstraints { (make) in
            make.left.equalToSuperview().inset(20)
            make.top.equalTo(baseLine.snp.bottom).offset(18)
        }
        
        moonsetTimeLabel.font = AppFont.SFPro.bold(size: 14)
        moonsetTimeLabel.textColor = ThemeManager.currentTheme.secondaryTextColor
        moonsetTimeLabel.textAlignment = .right
        container.addSubview(moonsetTimeLabel)
        
        moonsetTimeLabel.snp.makeConstraints { (make) in
            make.right.equalToSuperview().inset(20)
            make.top.equalTo(baseLine.snp.bottom).offset(18)
        }
    }
    
    func prepareMoonCirle() {
        circleGradientLayer.colors = [UIColor(hex: 0x416bff).cgColor, UIColor(hex: 0x10bcff).cgColor]
        circleGradientLayer.startPoint = .init(x: 0.5, y: 0)
        circleGradientLayer.endPoint = .init(x: 0.5, y: 1)
        container.layer.addSublayer(circleGradientLayer)
        
        moonImageView.image = UIImage(named: "moon_path_waxingGibbous")
        moonImageView.contentMode = .scaleAspectFit
        moonImageView.frame = .init(x: 0, y: 0, width: 28, height: 28)
        container.addSubview(moonImageView)
    }
}
