//
//  PhotoEditorVC.swift
//  WoWonder
//
//  Created by iMac on 20/05/25.
//  Copyright © 2025 ScriptSun. All rights reserved.
//

import UIKit
import Foundation
import FittedSheets
import SDWebImage
import CropViewController

enum ToolType {
    case brush
    case text
    case eraser
    case filter
    case sticker
    case image
    case cropImage
    case bgColor
}

struct ToolModel {
    var name: String
    var icon: String
    var type: ToolType
    var color: String
}

protocol PhotoEditorVCDelegate {
    func handlePhotoEditorSaveButtonTap(image: UIImage)
}

class PhotoEditorVC: UIViewController {
    
    // MARK: - IBOutlets
    
    @IBOutlet weak var undoButton: UIButton!
    @IBOutlet weak var redoButton: UIButton!
    @IBOutlet weak var editorView: UIView!
    @IBOutlet weak var editorViewHeightConst: NSLayoutConstraint!
    @IBOutlet weak var editorViewWidthConst: NSLayoutConstraint!
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var drawView: SwiftyDrawView!
    @IBOutlet weak var collectionView: UICollectionView!
    
    // MARK: - Properties
    
    private var toolList: [ToolModel] = []
    var selectedImage: UIImage? = nil
    var selectedBrushSize: CGFloat = 7
    var selectedBrushOpacity: CGFloat = 1
    var selectedColor = BrushColorModel(id: 2, color: "#000000")
    var selectedShape = MagicBrushModel(id: 0, icon: "ic_brush", type: .draw)
    private var _selectedStickerView: StickerView?
    var selectedStickerView: StickerView? {
        get {
            return _selectedStickerView
        } set {
            if _selectedStickerView != newValue {
                if let selectedStickerView = _selectedStickerView {
                    selectedStickerView.showEditingHandlers = false
                }
                _selectedStickerView = newValue
            }
            if let selectedStickerView = _selectedStickerView {
                selectedStickerView.showEditingHandlers = true
                selectedStickerView.superview?.bringSubviewToFront(selectedStickerView)
            }
        }
    }
    let engine = PhotoFilterEngine()
    var delegate: PhotoEditorVCDelegate?
    
    // MARK: - View Life Cycles
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        self.initialConfig()
    }
    
    // MARK: - Selectors
    
    // Close Button Action
    @IBAction func closeButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let alertVC = R.storyboard.popup.photoEditorWarningAlertVC() {
            alertVC.delegate = self
            self.present(alertVC, animated: true, completion: nil)
        }
    }
    
    // Undo Button Action
    @IBAction func undoButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.drawView.undo()
        self.updateHistoryButtons()
    }
    
    // Redo Button Action
    @IBAction func redoButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.drawView.redo()
        self.updateHistoryButtons()
    }
    
    // Save Button Action
    @IBAction func saveButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.selectedStickerView?.showEditingHandlers = false
        if let image = self.editorView.render() {
            self.delegate?.handlePhotoEditorSaveButtonTap(image: image)
            self.navigationController?.popViewController(animated: true)
        }
    }
    
    // MARK: - Helper Functions
    
    // Initial Config
    func initialConfig() {
        self.setupUI()
        self.setupCollectionView()
        self.setEditingToolData()
        self.setupDrawView()
    }
    
    // Setup UI
    func setupUI() {
        self.setEditorView()
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        self.editorView.addGestureRecognizer(tapGesture)
    }
    
    @objc func handleTap(_ gesture: UITapGestureRecognizer) {
        self.selectedStickerView?.showEditingHandlers = false
    }
    
    func setEditorView() {
        if let image = self.selectedImage {
            self.imageView.image = image
            let mainHeight = self.view.height - self.view.safeAreaTop - self.view.safeAreaBottom - 44 - 89
            let mainWidth = self.view.width
            let imageHeight = (mainWidth * image.size.height) / image.size.width
            let imageWidth = (mainHeight * image.size.width) / image.size.height
            if image.size.height > image.size.width {
                if imageHeight > mainHeight {
                    self.editorViewHeightConst.constant = mainHeight
                    self.editorViewWidthConst.constant = imageWidth
                } else {
                    self.editorViewHeightConst.constant = imageHeight
                    self.editorViewWidthConst.constant = (imageHeight * image.size.width) / image.size.height
                }
            } else {
                self.editorViewWidthConst.constant = mainWidth
                self.editorViewHeightConst.constant = imageHeight
            }
            self.view.updateConstraintsIfNeeded()
            self.view.layoutIfNeeded()
        }
    }
    
    // Set Editing Tool Data
    func setEditingToolData() {
        self.toolList = [
            ToolModel(name: "Brush", icon: "ic_brush", type: .brush, color: "212121"),
            ToolModel(name: "Text", icon: "ic_text", type: .text, color: "212121"),
            ToolModel(name: "Filter", icon: "ic_filter", type: .filter, color: "212121"),
            ToolModel(name: "Sticker", icon: "ic_sticker", type: .sticker, color: "212121"),
            ToolModel(name: "Image", icon: "ic_image", type: .image, color: "212121"),
            ToolModel(name: "Crop", icon: "ic_crop", type: .cropImage, color: "212121")
        ]
        self.collectionView.reloadData()
    }
    
    // Setup Collection View
    func setupCollectionView() {
        self.collectionView.delegate = self
        self.collectionView.dataSource = self
        self.collectionView.register(UINib(resource: R.nib.photoEditingToolCell), forCellWithReuseIdentifier: R.reuseIdentifier.photoEditingToolCell.identifier)
        let flowLayout = CollectionViewCenteredFlowLayout()
        flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        self.collectionView.collectionViewLayout = flowLayout
    }
    
    // Setup Draw View
    func setupDrawView() {
        self.updateHistoryButtons()
        self.drawView.delegate = self
        self.drawView.brush.width = self.selectedBrushSize
        self.drawView.brush.opacity = self.selectedBrushOpacity
        self.drawView.brush.color = Color(UIColor(hex: self.selectedColor.color))
        switch self.selectedShape.type {
        case .line:
            self.drawView.drawMode = .line
            break
        case .ellipse:
            self.drawView.drawMode = .ellipse
            break
        case .rect:
            self.drawView.drawMode = .rect
            break
        case .draw:
            self.drawView.drawMode = .draw
        }
        self.drawView.allowedTouchTypes = [.finger, .pencil]
    }
    
    func updateHistoryButtons() {
        self.undoButton.isEnabled = drawView.canUndo
        self.redoButton.isEnabled = drawView.canRedo
    }
    
    func addImage(img: UIImageView) {
        let stickerView = StickerView.init(contentView: img)
        stickerView.center = CGPoint.init(x: self.editorView.frame.midX, y: self.editorView.frame.midY)
        stickerView.delegate = self
        stickerView.outlineBorderColor = UIColor(hex: "969696")
        stickerView.setImage(UIImage(named: "ic_remove")!, forHandler: StickerViewHandler.close)
        stickerView.setImage(UIImage(named: "rotate-right")!, forHandler: StickerViewHandler.rotate)
        stickerView.showEditingHandlers = true
        self.editorView.addSubview(stickerView)
        self.selectedStickerView = stickerView
    }
    
}

// MARK: - Extension

// MARK: Collection View Setup
extension PhotoEditorVC: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.toolList.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.photoEditingToolCell.identifier, for: indexPath) as! PhotoEditingToolCell
        let item = self.toolList[indexPath.item]
        cell.setData(data: item)
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let item = self.toolList[indexPath.item]
        switch item.name {
        case "Brush":
            let options = SheetOptions(pullBarHeight: 0, useFullScreenMode: false, useInlineMode: true)
            if let newVC = R.storyboard.photoEditor.photoEditingBrushToolVC() {
                newVC.delegate = self
                if self.drawView.brush.blendMode == .normal {
                    newVC.isEraser = false
                } else {
                    newVC.isEraser = true
                }
                newVC.selectedBrushSize = self.selectedBrushSize
                newVC.selectedBrushOpacity = self.selectedBrushOpacity
                newVC.selectedColor = self.selectedColor
                newVC.selectedShape = self.selectedShape
                let sheetController = SheetViewController(controller: newVC, sizes: [.intrinsic], options: options)
                sheetController.cornerRadius = 24
                sheetController.dismissOnPull = false
                sheetController.dismissOnOverlayTap = false
                sheetController.allowPullingPastMaxHeight = false
                sheetController.allowPullingPastMinHeight = false
                sheetController.animateIn(to: self.view, in: self)
            }
        case "Text":
            let options = SheetOptions(pullBarHeight: 0, useFullScreenMode: false, useInlineMode: true)
            if let newVC = R.storyboard.photoEditor.photoEditingTextToolVC() {
                newVC.delegate = self
                let sheetController = SheetViewController(controller: newVC, sizes: [.percent(0.7)], options: options)
                sheetController.cornerRadius = 24
                sheetController.dismissOnPull = false
                sheetController.dismissOnOverlayTap = false
                sheetController.allowPullingPastMaxHeight = false
                sheetController.allowPullingPastMinHeight = false
                sheetController.animateIn(to: self.view, in: self)
            }
        case "Filter":
            let options = SheetOptions(pullBarHeight: 0, useFullScreenMode: false, useInlineMode: true)
            if let newVC = R.storyboard.photoEditor.photoEditingFilterToolVC() {
                newVC.selectedImage = self.selectedImage
                newVC.delegate = self
                let sheetController = SheetViewController(controller: newVC, sizes: [.intrinsic], options: options)
                sheetController.cornerRadius = 24
                sheetController.dismissOnPull = false
                sheetController.dismissOnOverlayTap = false
                sheetController.allowPullingPastMaxHeight = false
                sheetController.allowPullingPastMinHeight = false
                sheetController.animateIn(to: self.view, in: self)
            }
        case "Sticker":
            let options = SheetOptions(pullBarHeight: 0, useFullScreenMode: false, useInlineMode: true)
            if let newVC = R.storyboard.photoEditor.photoEditingStickerToolVC() {
                newVC.delegate = self
                let sheetController = SheetViewController(controller: newVC, sizes: [.intrinsic], options: options)
                sheetController.cornerRadius = 24
                sheetController.dismissOnPull = false
                sheetController.dismissOnOverlayTap = false
                sheetController.allowPullingPastMaxHeight = false
                sheetController.allowPullingPastMinHeight = false
                sheetController.animateIn(to: self.view, in: self)
            }
        case "Image":
            let options = SheetOptions(pullBarHeight: 0, useFullScreenMode: false, useInlineMode: true)
            if let newVC = R.storyboard.photoEditor.photoEditingImageToolVC() {
                newVC.delegate = self
                let sheetController = SheetViewController(controller: newVC, sizes: [.intrinsic], options: options)
                sheetController.cornerRadius = 24
                sheetController.dismissOnPull = false
                sheetController.dismissOnOverlayTap = false
                sheetController.allowPullingPastMaxHeight = false
                sheetController.allowPullingPastMinHeight = false
                sheetController.animateIn(to: self.view, in: self)
            }
        case "Crop":
            if let image = self.selectedImage {
                let vc = CropViewController(croppingStyle: .default, image: image)
                vc.delegate = self
                self.present(vc, animated: true)
            }
        default:
            break
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets.zero
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
}

// MARK: SwiftyDrawViewDelegate
extension PhotoEditorVC: SwiftyDrawViewDelegate {
    
    func swiftyDraw(shouldBeginDrawingIn drawingView: SwiftyDrawView, using touch: UITouch) -> Bool {
        return true
    }
    
    func swiftyDraw(didBeginDrawingIn drawingView: SwiftyDrawView, using touch: UITouch) {
        self.updateHistoryButtons()
    }
    
    func swiftyDraw(isDrawingIn drawingView: SwiftyDrawView, using touch: UITouch) {
        
    }
    
    func swiftyDraw(didFinishDrawingIn drawingView: SwiftyDrawView, using touch: UITouch) {
        
    }
    
    func swiftyDraw(didCancelDrawingIn drawingView: SwiftyDrawView, using touch: UITouch) {
        
    }
    
}

// MARK: PhotoEditingBrushToolVCDelegate
extension PhotoEditorVC: PhotoEditingBrushToolVCDelegate {
    
    func handleEraserButtonTap(sender: UIButton) {
        if self.drawView.brush.blendMode == .normal {
            self.drawView.brush.blendMode = .clear
        } else {
            self.drawView.brush.blendMode = .normal
        }
    }
    
    func handleSelectedBrushColor(color: BrushColorModel) {
        self.selectedColor = color
        self.drawView.brush.color = Color(UIColor(hex: color.color))
        self.drawView.brush.blendMode = .normal
    }
    
    func handleSelectedBrushShape(shape: MagicBrushModel) {
        self.selectedShape = shape
        switch shape.type {
        case .line:
            self.drawView.drawMode = .line
            break
        case .ellipse:
            self.drawView.drawMode = .ellipse
            break
        case .rect:
            self.drawView.drawMode = .rect
            break
        case .draw:
            self.drawView.drawMode = .draw
        }
    }
    
    func handleChangedBrushSize(size: CGFloat) {
        self.selectedBrushSize = size
        self.drawView.brush.width = size
    }
    
    func handleChangedBrushOpacity(opacity: CGFloat) {
        self.selectedBrushOpacity = opacity
        self.drawView.brush.opacity = opacity
        self.drawView.brush.blendMode = .normal
    }
    
}

// MARK: PhotoEditingTextToolVCDelegate
extension PhotoEditorVC: PhotoEditingTextToolVCDelegate {
    
    func handlePhotoEditingText(sender: UILabel) {
        sender.sizeToFit()
        sender.setNeedsLayout()
        sender.layoutIfNeeded()
        if let image = sender.labelToImage() {
            let img = UIImageView(image: image)
            self.addImage(img: img)
        }
    }
    
}

// MARK: PhotoEditingStickerToolVCDelegate
extension PhotoEditorVC: PhotoEditingStickerToolVCDelegate {
    
    func handleStickerSelection(data: PhotoStickerModel) {
        let url = URL(string: data.url)
        SDWebImageManager.shared.loadImage(with: url, progress: nil) { image, data, error, cache, success, url in
            let img = UIImageView(image: image)
            self.addImage(img: img)
        }
    }
    
    func handleStickerSelection(data: String) {
        let image = data.emojiToImage(size: 70)
        let img = UIImageView(image: image)
        self.addImage(img: img)
    }
    
    func handleStickerSelection(data: PhotoWidgetModel) {
        let img = UIImageView(image: data.image)
        self.addImage(img: img)
    }
    
}

// MARK: StickerViewDelegate
extension PhotoEditorVC: StickerViewDelegate {
    
    func stickerViewDidBeginMoving(_ stickerView: StickerView) {
        self.selectedStickerView = stickerView
    }
    
    func stickerViewDidChangeMoving(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidEndMoving(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidBeginRotating(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidChangeRotating(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidEndRotating(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidClose(_ stickerView: StickerView) {
        
    }
    
    func stickerViewDidTap(_ stickerView: StickerView) {
        self.selectedStickerView = stickerView
    }
    
}

// MARK: PhotoEditingFilterToolVCDelegate
extension PhotoEditorVC: PhotoEditingFilterToolVCDelegate {
    
    func handlePhotoEditingCloseTap() {
        self.imageView.image = self.selectedImage
    }
    
    func handlePhotoEditingFilterSelection(data: PhotoFilterModel) {
        if let image = self.selectedImage {
            let filtered = self.engine.apply(filter: data.photoFilter, to: image)
            self.imageView.image = filtered
        }
    }
    
}

// MARK: PhotoEditingImageToolVCDelegate
extension PhotoEditorVC: PhotoEditingImageToolVCDelegate {
    
    func handleAIImageGenerate(image_url: String) {
        
    }
    
}

// MARK: CropViewControllerDelegate
extension PhotoEditorVC: CropViewControllerDelegate {
    
    func cropViewController(_ cropViewController: CropViewController, didCropToImage image: UIImage, withRect cropRect: CGRect, angle: Int) {
        cropViewController.dismiss(animated: true)
        self.selectedImage = image
        self.setEditorView()
    }
    
}

// MARK: PhotoEditorWarningAlertVCDelegate
extension PhotoEditorVC: PhotoEditorWarningAlertVCDelegate {
    
    func photoEditorWarningAlertSAVEButtonPressed(_ sender: UIButton) {
        self.selectedStickerView?.showEditingHandlers = false
        if let image = self.editorView.render() {
            self.delegate?.handlePhotoEditorSaveButtonTap(image: image)
            self.navigationController?.popViewController(animated: true)
        }
    }
    
    func photoEditorWarningAlertDISCARDButtonPressed(_ sender: UIButton) {
        self.navigationController?.popViewController(animated: true)
    }
    
}

extension UILabel {
    
    /*func labelToImage() -> UIImage? {
        let scale: CGFloat = 2
        let size = self.frame.size.applying(CGAffineTransform(scaleX: scale, y: scale))
        UIGraphicsBeginImageContextWithOptions(size, false, 0)
        guard let ctx = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        self.frame.size = size
        self.font = self.font.withSize(self.font.pointSize * scale)
        self.layer.render(in: ctx)
        let baseImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return baseImage
    }*/
    
    func labelToImage() -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)
        guard let ctx = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        self.layer.render(in: ctx)
        let baseImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return baseImage
    }
    
}

extension UIView {
    
    public func render() -> UIImage? {
        return renderTextOnView()
    }
    
    private func renderTextOnView() -> UIImage? {
        // 1. Create a bitmap context matching the view’s bounds (scale=0 → device screen scale)
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)
        guard let ctx = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        
        // 2. Tell the view’s layer to draw itself into our context
        self.layer.render(in: ctx)
        let baseImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        // 3. If it worked, pass that image into the step-2 function
        if let img = baseImage {
            return renderTextOnImage(img)
        } else {
            return nil
        }
    }
    
    private func renderTextOnImage(_ image: UIImage) -> UIImage? {
        // Keep the view’s original background color so we can restore it after
        let originalBG = self.layer.backgroundColor
        
        // Make a new context the same size as the view
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)
        guard let ctx = UIGraphicsGetCurrentContext() else {
            UIGraphicsEndImageContext()
            return nil
        }
        
        // Compute a scale so that image.width / scale == view.bounds.width
        // (This assumes image.size.width originally matched view.bounds.width * screenScale)
        let scaleFactor = image.size.width / self.bounds.width
        
        // Center the first image inside the view’s rectangle
        let drawWidth = image.size.width / scaleFactor
        let drawHeight = image.size.height / scaleFactor
        let drawX = (self.bounds.width  - drawWidth)  / 2.0
        let drawY = (self.bounds.height - drawHeight) / 2.0
        
        image.draw(in: CGRect(x: drawX,
                              y: drawY,
                              width: drawWidth,
                              height: drawHeight))
        
        // Temporarily clear the view’s background, render its layers “on top,” then restore BG
        self.layer.backgroundColor = UIColor.clear.cgColor
        self.layer.render(in: ctx)
        self.layer.backgroundColor = originalBG
        
        // Grab the combined image
        let combined = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        // Return a properly‐scaled UIImage
        if let cg = combined?.cgImage {
            return UIImage(cgImage: cg,
                           scale: combined!.scale,
                           orientation: combined!.imageOrientation)
        } else {
            return nil
        }
    }
}
