import UIKit

public enum DeviceType {
    case phone
    case tablet
}

public enum DeviceMetrics: CaseIterable, Equatable {
    case iPhone4
    case iPhone5
    case iPhone6
    case iPhone6Plus
    case iPhoneX
    case iPhoneXSMax
    case iPad
    case iPadPro10Inch
    case iPadPro11Inch
    case iPadPro
    case iPadPro3rdGen
    case unknown(screenSize: CGSize, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?)

    public static var allCases: [DeviceMetrics] {
        return [
            .iPhone4,
            .iPhone5,
            .iPhone6,
            .iPhone6Plus,
            .iPhoneX,
            .iPhoneXSMax,
            .iPad,
            .iPadPro10Inch,
            .iPadPro11Inch,
            .iPadPro,
            .iPadPro3rdGen
        ]
    }
    
    public init(screenSize: CGSize, statusBarHeight: CGFloat, onScreenNavigationHeight: CGFloat?) {
        var screenSize = screenSize
        if screenSize.width > screenSize.height {
            screenSize = CGSize(width: screenSize.height, height: screenSize.width)
        }
        
        let additionalSize = CGSize(width: screenSize.width, height: screenSize.height + 20.0)
        for device in DeviceMetrics.allCases {
            if let _ = onScreenNavigationHeight, device.onScreenNavigationHeight(inLandscape: false, systemOnScreenNavigationHeight: nil) == nil {
                if case .tablet = device.type {
                    if screenSize.height == 1024.0 && screenSize.width == 768.0 {
                    } else {
                        continue
                    }
                } else {
                    continue
                }
            }
            
            let width = device.screenSize.width
            let height = device.screenSize.height
            if ((screenSize.width.isEqual(to: width) && screenSize.height.isEqual(to: height)) || (additionalSize.width.isEqual(to: width) && additionalSize.height.isEqual(to: height))) {
                self = device
                return
            }
        }
        self = .unknown(screenSize: screenSize, statusBarHeight: statusBarHeight, onScreenNavigationHeight: onScreenNavigationHeight)
    }
    
    public var type: DeviceType {
        switch self {
            case .iPad, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
                return .tablet
            case let .unknown(screenSize, _, _) where screenSize.width >= 768.0 && screenSize.height >= 1024.0:
                return .tablet
            default:
                return .phone
        }
    }
    
    var screenSize: CGSize {
        switch self {
            case .iPhone4:
                return CGSize(width: 320.0, height: 480.0)
            case .iPhone5:
                return CGSize(width: 320.0, height: 568.0)
            case .iPhone6:
                return CGSize(width: 375.0, height: 667.0)
            case .iPhone6Plus:
                return CGSize(width: 414.0, height: 736.0)
            case .iPhoneX:
                return CGSize(width: 375.0, height: 812.0)
            case .iPhoneXSMax:
                return CGSize(width: 414.0, height: 896.0)
            case .iPad:
                return CGSize(width: 768.0, height: 1024.0)
            case .iPadPro10Inch:
                return CGSize(width: 834.0, height: 1112.0)
            case .iPadPro11Inch:
                return CGSize(width: 834.0, height: 1194.0)
            case .iPadPro, .iPadPro3rdGen:
                return CGSize(width: 1024.0, height: 1366.0)
            case let .unknown(screenSize, _, _):
                return screenSize
        }
    }
    
    func safeInsets(inLandscape: Bool) -> UIEdgeInsets {
        switch self {
            case .iPhoneX, .iPhoneXSMax:
                return inLandscape ? UIEdgeInsets(top: 0.0, left: 44.0, bottom: 0.0, right: 44.0) : UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
            default:
                return UIEdgeInsets.zero
        }
    }
    
    func onScreenNavigationHeight(inLandscape: Bool, systemOnScreenNavigationHeight: CGFloat?) -> CGFloat? {
        switch self {
        case .iPhoneX, .iPhoneXSMax:
            return inLandscape ? 21.0 : 34.0
        case .iPadPro3rdGen, .iPadPro11Inch:
            return 21.0
        case .iPad, .iPadPro, .iPadPro10Inch:
            if let systemOnScreenNavigationHeight = systemOnScreenNavigationHeight, !systemOnScreenNavigationHeight.isZero {
                return 21.0
            } else {
                return nil
            }
        case let .unknown(_, _, onScreenNavigationHeight):
            return onScreenNavigationHeight
        default:
            return nil
        }
    }
    
    func statusBarHeight(for size: CGSize) -> CGFloat? {
        let value = self.statusBarHeight
        switch self {
        case .iPad, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
            return value
        default:
            if size.width < size.height {
                return value
            } else {
                return nil
            }
        }
    }
    
    var statusBarHeight: CGFloat {
        switch self {
            case .iPhoneX, .iPhoneXSMax:
                return 44.0
            case .iPadPro11Inch, .iPadPro3rdGen:
                return 24.0
            case let .unknown(_, statusBarHeight, _):
                return statusBarHeight
            default:
                return 20.0
        }
    }
    
    public func keyboardHeight(inLandscape: Bool) -> CGFloat {
        if inLandscape {
            switch self {
                case .iPhone4, .iPhone5:
                    return 162.0
                case .iPhone6, .iPhone6Plus:
                    return 163.0
                case .iPhoneX, .iPhoneXSMax:
                    return 172.0
                case .iPad, .iPadPro10Inch:
                    return 348.0
                case .iPadPro11Inch:
                    return 368.0
                case .iPadPro:
                    return 421.0
                case .iPadPro3rdGen:
                    return 441.0
                case .unknown:
                    return 216.0
            }
        } else {
            switch self {
                case .iPhone4, .iPhone5, .iPhone6:
                    return 216.0
                case .iPhone6Plus:
                    return 226.0
                case .iPhoneX:
                    return 291.0
                case .iPhoneXSMax:
                    return 302.0
                case .iPad, .iPadPro10Inch:
                    return 263.0
                case .iPadPro11Inch:
                    return 283.0
                case .iPadPro:
                    return 328.0
                case .iPadPro3rdGen:
                    return 348.0
                case .unknown:
                    return 216.0
            }
        }
    }
    
    func predictiveInputHeight(inLandscape: Bool) -> CGFloat {
        if inLandscape {
            switch self {
                case .iPhone4, .iPhone5, .iPhone6, .iPhone6Plus, .iPhoneX, .iPhoneXSMax:
                    return 37.0
                case .iPad, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
                    return 50.0
                case .unknown:
                    return 37.0
            }
        } else {
            switch self {
                case .iPhone4, .iPhone5:
                    return 37.0
                case .iPhone6, .iPhoneX, .iPhoneXSMax:
                    return 44.0
                case .iPhone6Plus:
                    return 45.0
                case .iPad, .iPadPro10Inch, .iPadPro11Inch, .iPadPro, .iPadPro3rdGen:
                    return 50.0
                case .unknown:
                    return 44.0
            }
        }
    }
    
    public func previewingContentSize(inLandscape: Bool) -> CGSize {
        let screenSize = self.screenSize
        if inLandscape {
            switch self {
                case .iPhone5:
                    return CGSize(width: screenSize.height, height: screenSize.width - 10.0)
                case .iPhone6:
                    return CGSize(width: screenSize.height, height: screenSize.width - 22.0)
                case .iPhone6Plus:
                    return CGSize(width: screenSize.height, height: screenSize.width - 22.0)
                case .iPhoneX:
                    return CGSize(width: screenSize.height, height: screenSize.width + 48.0)
                case .iPhoneXSMax:
                    return CGSize(width: screenSize.height, height: screenSize.width - 30.0)
                default:
                    return CGSize(width: screenSize.height, height: screenSize.width - 10.0)
            }
        } else {
            switch self {
                case .iPhone5:
                    return CGSize(width: screenSize.width, height: screenSize.height - 50.0)
                case .iPhone6:
                    return CGSize(width: screenSize.width, height: screenSize.height - 97.0)
                case .iPhone6Plus:
                    return CGSize(width: screenSize.width, height: screenSize.height - 95.0)
                case .iPhoneX:
                    return CGSize(width: screenSize.width, height: screenSize.height - 154.0)
                case .iPhoneXSMax:
                    return CGSize(width: screenSize.width, height: screenSize.height - 84.0)
                default:
                    return CGSize(width: screenSize.width, height: screenSize.height - 50.0)
            }
        }
    }
    
    public var hasTopNotch: Bool {
        switch self {
            case .iPhoneX, .iPhoneXSMax:
                return true
            default:
                return false
        }
    }
}