//
//  Random.swift
//  Feels
//
//  Created by Trey Tartt on 1/9/22.
//

import Foundation
import SwiftUI

struct Constants {
    static let groupShareId = "group.com.88oakapps.ifeel"
    static let groupShareIdDebug = "group.com.88oakapps.ifeelDebug"
    
    static let viewsCornerRaidus: CGFloat = 10
}

struct GroupUserDefaults {
    static var groupDefaults: UserDefaults {
#if DEBUG
        return UserDefaults(suiteName: Constants.groupShareIdDebug)!
#else
        return UserDefaults(suiteName: Constants.groupShareId)!
#endif
    }
}

class Random {
    static var tomorrowMidnightThirty: Date {
        let components = DateComponents(hour: 0, minute: 30, second: 0)
        var updateTime = Date()
        if let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date()),
           let tomorrowMorning = Calendar.current.date(byAdding: components, to: tomorrow) {
            updateTime = tomorrowMorning
        }
        return updateTime
    }
    
    static var existingWeekdayName = [Int: String]()
    static func weekdayName(fromDate date: Date) -> String {
        let weekday = Calendar.current.component(.weekday, from: date)
        let calendar = Calendar.current
        let dayIndex = ((weekday - 1) + (calendar.firstWeekday - 1)) % 7
        if let value = Random.existingWeekdayName[dayIndex] {
            return value
        }
        let newValue = calendar.weekdaySymbols[dayIndex]
        Random.existingWeekdayName[dayIndex] = newValue
        return newValue
    }
    
    static func monthName(fromMonthInt: Int) -> String {
        let monthName = DateFormatter().monthSymbols[fromMonthInt-1]
        return monthName
    }
    
    static var existingDayFormat = [NSNumber: String]()
    static func dayFormat(fromDate date: Date) -> String {
        let components = Calendar.current.dateComponents([.day], from: date)
        let day = components.day!
        
        let formatter = NumberFormatter()
        formatter.numberStyle = .ordinal
        let num = NSNumber(integerLiteral: day)
        if let value = existingDayFormat[num] {
            return value
        }
        let newValue = formatter.string(from: num) ?? ""
        existingDayFormat[num] = newValue
        return newValue
    }
    
    static func createTotalPerc(fromEntries entries: [MoodEntry]) -> [MoodMetrics] {
        let filteredEntries = entries.filter({
            return ![.missing, .placeholder].contains($0.mood)
        })
        var returnData = [MoodMetrics]()
        
        for (_, mood) in Mood.allValues.enumerated() {
            let moodEntries = filteredEntries.filter({
                Int($0.moodValue) == mood.rawValue
            })
            let total = moodEntries.count
            let perc = (Float(total) / Float(filteredEntries.count)) * 100
            returnData.append(MoodMetrics(mood: mood, total: total, percent: perc))
        }
        
        returnData = returnData.sorted(by: {
            $0.mood.rawValue > $1.mood.rawValue
        })
        
        return returnData
    }
}

struct RoundedCorner: Shape {
    
    var radius: CGFloat = .infinity
    var corners: UIRectCorner = .allCorners
    
    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

extension View {
    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
        clipShape( RoundedCorner(radius: radius, corners: corners) )
    }
    
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view
        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
    
    func asImage(size: CGSize) -> UIImage {
        let controller = UIHostingController(rootView: self)
        controller.view.bounds = CGRect(origin: .zero, size: size)
        let image = controller.view.asImage()
        return image
    }
}

extension UIView {
    func asImage() -> UIImage {
        let format = UIGraphicsImageRendererFormat()
        format.scale = 1
        return UIGraphicsImageRenderer(size: self.layer.frame.size, format: format).image { context in
            self.drawHierarchy(in: self.layer.bounds, afterScreenUpdates: true)
        }
    }
}

extension Color {
    static func random() -> Self {
        Self(
            red: .random(in: 0...1),
            green: .random(in: 0...1),
            blue: .random(in: 0...1)
        )
    }
    
    public func lighter(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).lighter(by: amount)) }
    public func darker(by amount: CGFloat = 0.2) -> Self { Self(UIColor(self).darker(by: amount)) }
}

extension String {
    func textToImage() -> UIImage? {
        let nsString = (self as NSString)
        let font = UIFont.systemFont(ofSize: 100) // you can change your font size here
        let stringAttributes = [NSAttributedString.Key.font: font]
        let imageSize = nsString.size(withAttributes: stringAttributes)
        
        UIGraphicsBeginImageContextWithOptions(imageSize, false, 0) //  begin image context
        UIColor.clear.set() // clear background
        UIRectFill(CGRect(origin: CGPoint(), size: imageSize)) // set rect size
        nsString.draw(at: CGPoint.zero, withAttributes: stringAttributes) // draw text within rect
        let image = UIGraphicsGetImageFromCurrentImageContext() // create image from context
        UIGraphicsEndImageContext() //  end image context
        
        return image ?? UIImage()
    }
}

extension UIColor {
    
    func lighter(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjust(by: abs(percentage))
    }
    
    func darker(by percentage: CGFloat = 10.0) -> UIColor {
        return self.adjust(by: -abs(percentage))
    }
    
    func adjust(by percentage: CGFloat) -> UIColor {
        var alpha, hue, saturation, brightness, red, green, blue, white : CGFloat
        (alpha, hue, saturation, brightness, red, green, blue, white) = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
        
        let multiplier = percentage / 100.0
        
        if self.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha) {
            let newBrightness: CGFloat = max(min(brightness + multiplier*brightness, 1.0), 0.0)
            return UIColor(hue: hue, saturation: saturation, brightness: newBrightness, alpha: alpha)
        }
        else if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
            let newRed: CGFloat = min(max(red + multiplier*red, 0.0), 1.0)
            let newGreen: CGFloat = min(max(green + multiplier*green, 0.0), 1.0)
            let newBlue: CGFloat = min(max(blue + multiplier*blue, 0.0), 1.0)
            return UIColor(red: newRed, green: newGreen, blue: newBlue, alpha: alpha)
        }
        else if self.getWhite(&white, alpha: &alpha) {
            let newWhite: CGFloat = (white + multiplier*white)
            return UIColor(white: newWhite, alpha: alpha)
        }
        
        return self
    }
}

extension Bundle {
    var appName: String {
        return infoDictionary?["CFBundleName"] as! String
    }

    var bundleId: String {
        return bundleIdentifier!
    }

    var versionNumber: String {
        return infoDictionary?["CFBundleShortVersionString"] as! String
    }

    var buildNumber: String {
        return infoDictionary?["CFBundleVersion"] as! String
    }
}
