//
//  LNOrderRoomGuideView.swift
//  Gami
//
//  Created by OneeChan on 2026/3/22.
//

import Foundation
import UIKit
import SnapKit


class LNOrderRoomGuideView: UIView {
    static weak var joinView: UIView?
    static weak var mainSeatView: UIView?
    static weak var playmateView: UIView?
    static weak var orderCardView: UIView?
    private static weak var currentGuide: LNOrderRoomGuideView?

    private enum Step: Int, CaseIterable {
        case join
        case demand
        case playmate
        case order

        var cardSize: CGSize {
            switch self {
            case .join, .playmate, .order:
                .init(width: 314, height: self == .join ? 136 : 120)
            case .demand:
                .init(width: 320, height: 136)
            }
        }

        var focusInset: UIEdgeInsets {
            switch self {
            case .join:
                .init(top: -4, left: -4, bottom: -4, right: -4)
            case .demand:
                .init(top: -8, left: -4, bottom: -8, right: -4)
            case .playmate:
                .init(top: -16, left: -4, bottom: -16, right: -4)
            case .order:
                .init(top: -2, left: -2, bottom: -2, right: -2)
            }
        }

        var focusCornerRadius: CGFloat {
            switch self {
            case .join:
                15
            case .demand, .playmate:
                12
            case .order:
                12
            }
        }

        var progressText: String {
            "(\(rawValue + 1)/\(Self.allCases.count))"
        }
    }

    private let dimLayer = CAShapeLayer()
    private let lineLayer = CAShapeLayer()

    private let dotView = UIView()
    private let dotInnerView = UIView()

    private let cardView = UIView()
    private let cardGlowView = UIImageView(image: .primary_6)
    private let titleLabel = UILabel()
    private let descLabel = UILabel()
    private let nextButton = UIButton(type: .custom)
    private let nextTitleLabel = UILabel()
    private let progressLabel = UILabel()
    
    private weak var profileCard: LNRoomProfileCardPanel?

    private var currentStep: Step = .join {
        didSet {
            updateTexts()
            setNeedsLayout()
        }
    }

    static func show(_ container: UIView) {
        guard currentGuide == nil else { return }

        let guide = LNOrderRoomGuideView()
        currentGuide = guide
        container.addSubview(guide)
        guide.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        setupViews()
        updateTexts()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        dimLayer.frame = bounds
        lineLayer.frame = bounds
        updateLayout()
    }
}

private extension LNOrderRoomGuideView {
    var currentAnchorView: UIView? {
        switch currentStep {
        case .join:
            Self.joinView
        case .demand:
            Self.mainSeatView
        case .playmate:
            Self.playmateView
        case .order:
            Self.orderCardView
        }
    }

    func setupViews() {
        backgroundColor = .clear

        dimLayer.fillColor = UIColor.black.withAlphaComponent(0.6).cgColor
        dimLayer.fillRule = .evenOdd
        layer.addSublayer(dimLayer)

        lineLayer.strokeColor = UIColor.fill.cgColor
        lineLayer.lineWidth = 1
        lineLayer.fillColor = UIColor.clear.cgColor
        layer.addSublayer(lineLayer)

        dotView.backgroundColor = UIColor.fill.withAlphaComponent(0.2)
        dotView.layer.cornerRadius = 7.5
        addSubview(dotView)

        dotInnerView.backgroundColor = .fill
        dotInnerView.layer.cornerRadius = 3.5
        dotView.addSubview(dotInnerView)
        dotInnerView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.width.height.equalTo(7)
        }

        cardView.backgroundColor = .fill
        cardView.layer.cornerRadius = 20
        cardView.clipsToBounds = true
        addSubview(cardView)
        cardView.frame = .init(x: 0, y: 0, width: 50, height: 50)

        cardGlowView.alpha = 0.6
        cardGlowView.contentMode = .scaleToFill
        cardView.addSubview(cardGlowView)
        cardGlowView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }

        titleLabel.font = .heading_h3
        titleLabel.textColor = .text_5
        titleLabel.numberOfLines = 0
        cardView.addSubview(titleLabel)
        titleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(20)
            make.leading.equalToSuperview().offset(15)
            make.trailing.equalToSuperview().offset(-15)
        }

        descLabel.font = .body_m
        descLabel.textColor = .text_4
        descLabel.numberOfLines = 0
        cardView.addSubview(descLabel)
        descLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(8)
            make.leading.equalToSuperview().offset(15)
            make.trailing.equalToSuperview().offset(-15)
        }

        nextButton.setBackgroundImage(.primary_7, for: .normal)
        nextButton.layer.cornerRadius = 16.5
        nextButton.clipsToBounds = true
        nextButton.addAction(UIAction(handler: { [weak self] _ in
            self?.handleNext()
        }), for: .touchUpInside)
        cardView.addSubview(nextButton)
        nextButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-15)
            make.bottom.equalToSuperview().offset(-13)
            make.height.equalTo(33)
        }

        let buttonStack = UIStackView()
        buttonStack.axis = .horizontal
        buttonStack.spacing = 2
        buttonStack.alignment = .center
        buttonStack.isUserInteractionEnabled = false
        nextButton.addSubview(buttonStack)
        buttonStack.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(12)
            make.trailing.equalToSuperview().offset(-12)
            make.centerY.equalToSuperview()
        }

        nextTitleLabel.font = .heading_h3
        nextTitleLabel.textColor = .text_1
        buttonStack.addArrangedSubview(nextTitleLabel)

        progressLabel.font = .body_xs
        progressLabel.textColor = .text_1
        buttonStack.addArrangedSubview(progressLabel)
    }

    func updateTexts() {
        nextTitleLabel.text = .init(key: "A00373")
        progressLabel.text = currentStep.progressText

        switch currentStep {
        case .join:
            titleLabel.text = .init(key: "A00374")
            descLabel.attributedText = nil
            descLabel.text = .init(key: "A00375")
        case .demand:
            titleLabel.text = .init(key: "A00376")
            descLabel.attributedText = highlightedDemandText()
        case .playmate:
            titleLabel.text = .init(key: "A00381")
            descLabel.attributedText = nil
            descLabel.text = .init(key: "A00382")
        case .order:
            titleLabel.text = .init(key: "A00383")
            descLabel.attributedText = nil
            descLabel.text = .init(key: "A00384")
        }
    }

    func highlightedDemandText() -> NSAttributedString {
        let text = String(key: "A00378")
        let attributed = NSMutableAttributedString(
            string: text,
            attributes: [
                .font: UIFont.body_m,
                .foregroundColor: UIColor.text_4
            ]
        )
        [String(key: "A00379"), String(key: "A00380"), String(key: "A00385")].forEach { target in
            let nsText = text as NSString
            let range = nsText.range(of: target)
            if range.location != NSNotFound {
                attributed.addAttributes([
                    .foregroundColor: UIColor.text_6
                ], range: range)
            }
        }
        return attributed
    }

    func updateLayout() {
        guard let focusRect = currentFocusRect() else {
            dimLayer.path = UIBezierPath(rect: bounds).cgPath
            lineLayer.path = nil
            dotView.isHidden = true
            cardView.isHidden = true
            return
        }

        cardView.isHidden = false
        dotView.isHidden = false

        let cardFrame = currentCardFrame(for: focusRect)
        cardView.frame = cardFrame

        let maskPath = UIBezierPath(rect: bounds)
        maskPath.append(UIBezierPath(roundedRect: focusRect, cornerRadius: currentStep.focusCornerRadius))
        dimLayer.path = maskPath.cgPath

        let isCardAbove = cardFrame.maxY <= focusRect.minY
        let dotCenter = CGPoint(
            x: currentStep == .demand ? focusRect.maxX - 42 : focusRect.midX,
            y: isCardAbove ? focusRect.minY - 7.5 : focusRect.maxY + 7.5
        )
        dotView.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)
        dotView.center = dotCenter

        let path = UIBezierPath()
        path.move(to: CGPoint(x: dotCenter.x, y: isCardAbove ? cardFrame.maxY : cardFrame.minY))
        path.addLine(to: dotCenter)
        lineLayer.path = path.cgPath
    }

    func currentFocusRect() -> CGRect? {
        guard let anchor = currentAnchorView,
              anchor.window != nil else {
            return nil
        }

        let rect = anchor.convert(anchor.bounds, to: self)
        let inset = currentStep.focusInset
        let focusedRect = rect.inset(by: inset)
        let visibleRect = focusedRect.intersection(bounds)
        guard !visibleRect.isNull, !visibleRect.isEmpty else { return nil }
        return visibleRect
    }

    func currentCardFrame(for focusRect: CGRect) -> CGRect {
        let size = currentStep.cardSize
        switch currentStep {
        case .join:
            let x = bounds.width - 12 - size.width
            let y = focusRect.minY - 56 - size.height
            return .init(x: x, y: max(100, y), width: size.width, height: size.height)
        case .demand:
            let x = bounds.width - 12 - size.width
            return .init(x: x, y: focusRect.maxY + 61, width: size.width, height: size.height)
        case .playmate:
            return .init(x: (bounds.width - size.width) / 2, y: focusRect.maxY + 59, width: size.width, height: size.height)
        case .order:
            let y = focusRect.minY - 66 - size.height
            return .init(x: 10, y: max(100, y), width: size.width, height: size.height)
        }
    }

    func handleNext() {
        switch currentStep {
        case .join:
            currentStep = .demand
        case .demand:
            currentStep = .playmate
        case .playmate:
            showOrderStepIfPossible()
        case .order:
            dismiss()
            profileCard?.dismiss(animated: false)
        }
    }

    func showOrderStepIfPossible() {
        let panel = LNRoomProfileCardPanel()
        panel.toBeExample()
        panel.popup(superview, animated: false)
        superview?.bringSubviewToFront(self)
        profileCard = panel
        
        currentStep = .order
    }

    func dismiss() {
        if Self.currentGuide === self {
            Self.currentGuide = nil
        }

        UIView.animate(withDuration: 0.2, animations: {
            self.alpha = 0
        }, completion: { [weak self] _ in
            self?.removeFromSuperview()
        })
    }
}
