//
//  TaskAddViewController.swift
//  suixinkan
//

import PhotosUI
import SnapKit
import UIKit
import UniformTypeIdentifiers

/// 添加任务页，对齐 Android `TaskAddScreen`。
final class TaskAddViewController: BaseViewController {

    private let viewModel = TaskAddViewModel()
    private let taskAPI = NetworkServices.shared.taskAPI
    private let ossUploadService = NetworkServices.shared.ossUploadService

    private let scrollView = UIScrollView()
    private let contentStack = UIStackView()
    private let mediaSection = TaskAddMediaSectionView()
    private let prioritySection = TaskPrioritySectionView()
    private let orderButton = TaskOrderSelectButton()
    private let nameField = TaskBorderTextField(placeholder: "请输入任务标题")
    private let detailsField = TaskBorderTextView(placeholder: "请输入任务描述（必填）")
    private let saveButton = AppButton(title: "保存")
    private let bottomBar = UIView()

    private var remarkDialog: TaskFileRemarkDialogView?
    private var pickingMediaType: Int = 2
    private var detailsPlaceholder = "请输入任务描述（必填）"

    override func setupNavigationBar() {
        title = "添加任务"
    }

    override func setupUI() {
        contentStack.axis = .vertical
        contentStack.spacing = AppSpacing.sm

        bottomBar.backgroundColor = .white
        view.addSubview(scrollView)
        view.addSubview(bottomBar)
        scrollView.addSubview(contentStack)

        contentStack.addArrangedSubview(mediaSection)
        contentStack.addArrangedSubview(prioritySection)
        contentStack.addArrangedSubview(orderButton)
        contentStack.addArrangedSubview(nameField)
        contentStack.addArrangedSubview(detailsField)
        bottomBar.addSubview(saveButton)
    }

    override func setupConstraints() {
        bottomBar.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
        }
        saveButton.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(AppSpacing.md)
        }
        scrollView.snp.makeConstraints { make in
            make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            make.bottom.equalTo(bottomBar.snp.top)
        }
        contentStack.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(AppSpacing.md)
            make.width.equalTo(scrollView.snp.width).offset(-AppSpacing.md * 2)
        }
    }

    override func bindActions() {
        viewModel.onStateChange = { [weak self] in
            Task { @MainActor in self?.applyViewModel() }
        }
        viewModel.onShowMessage = { [weak self] message in
            Task { @MainActor in self?.showToast(message) }
        }

        mediaSection.onCloudImport = { [weak self] in self?.openCloudPicker() }
        mediaSection.onLocalImport = { [weak self] in self?.presentLocalImportSheet() }
        mediaSection.onFileTap = { [weak self] file in self?.viewModel.presentRemarkDialog(for: file.id) }
        mediaSection.onDeleteFile = { [weak self] file in self?.confirmDelete(file: file) }

        prioritySection.onUrgentHourChange = { [weak self] hour in
            self?.viewModel.setUrgentHour(hour)
        }
        prioritySection.onCustomHourTextChange = { [weak self] text in
            self?.viewModel.updateCustomUrgentHourText(text)
        }

        orderButton.addTarget(self, action: #selector(openOrderSelect), for: .touchUpInside)
        nameField.textField.addTarget(self, action: #selector(nameChanged), for: .editingChanged)
        detailsField.textView.delegate = self
        saveButton.addTarget(self, action: #selector(saveTapped), for: .touchUpInside)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if let fileID = viewModel.consumePendingRemarkFileID() {
            viewModel.presentRemarkDialog(for: fileID)
        }
    }

    @MainActor
    private func applyViewModel() {
        mediaSection.apply(files: viewModel.selectedFiles)
        prioritySection.apply(urgentHour: viewModel.urgentHour)
        orderButton.apply(orderNumber: viewModel.selectedOrderNumber)
        if nameField.textField.text != viewModel.taskName {
            nameField.textField.text = viewModel.taskName
        }
        if detailsField.textView.textColor != AppColor.textTertiary,
           detailsField.textView.text != viewModel.taskDetails {
            detailsField.textView.text = viewModel.taskDetails
        }
        saveButton.isEnabled = !viewModel.isUploading

        if viewModel.showRemarkDialog, let file = viewModel.remarkTargetFile {
            showRemarkDialog(file: file)
        } else {
            hideRemarkDialog()
        }

        if viewModel.showSuccessDialog {
            presentSuccessDialog()
        }
    }

    @objc private func nameChanged() {
        viewModel.updateTaskName(nameField.textField.text ?? "")
    }

    @objc private func openOrderSelect() {
        let controller = TaskOrderSelectViewController(initialOrderNumber: viewModel.selectedOrderNumber)
        controller.onConfirmed = { [weak self] orderNumber in
            self?.viewModel.setSelectedOrderNumber(orderNumber)
        }
        navigationController?.pushViewController(controller, animated: true)
    }

    private func openCloudPicker() {
        let controller = CloudStoragePickForTaskViewController(
            importedFileIDs: viewModel.importedCloudFileIDs
        )
        controller.onConfirmed = { [weak self] files in
            self?.viewModel.addCloudFiles(files)
            if let fileID = self?.viewModel.consumePendingRemarkFileID() {
                self?.viewModel.presentRemarkDialog(for: fileID)
            }
        }
        navigationController?.pushViewController(controller, animated: true)
    }

    private func presentLocalImportSheet() {
        let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
        sheet.addAction(UIAlertAction(title: "图片", style: .default) { [weak self] _ in
            self?.presentMediaPicker(isImage: true)
        })
        sheet.addAction(UIAlertAction(title: "视频", style: .default) { [weak self] _ in
            self?.presentMediaPicker(isImage: false)
        })
        sheet.addAction(UIAlertAction(title: "取消", style: .cancel))
        present(sheet, animated: true)
    }

    private func presentMediaPicker(isImage: Bool) {
        pickingMediaType = isImage ? 2 : 1
        var configuration = PHPickerConfiguration(photoLibrary: .shared())
        configuration.filter = isImage ? .images : .videos
        configuration.selectionLimit = 50
        let picker = PHPickerViewController(configuration: configuration)
        picker.delegate = self
        present(picker, animated: true)
    }

    private func confirmDelete(file: TaskFileItem) {
        let alert = UIAlertController(title: "删除确认", message: "确定要删除此文件吗？", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        alert.addAction(UIAlertAction(title: "确定", style: .default) { [weak self] _ in
            self?.viewModel.removeTaskFile(id: file.id)
        })
        present(alert, animated: true)
    }

    @objc private func saveTapped() {
        showLoading()
        Task {
            await viewModel.validateAndSubmit(api: taskAPI)
            hideLoading()
        }
    }

    private func presentSuccessDialog() {
        guard viewModel.showSuccessDialog else { return }
        let alert = UIAlertController(
            title: "添加成功",
            message: "任务已成功添加。是否继续添加新任务？",
            preferredStyle: .alert
        )
        alert.addAction(UIAlertAction(title: "继续添加", style: .default) { [weak self] _ in
            self?.viewModel.handleContinueAdding()
        })
        alert.addAction(UIAlertAction(title: "返回", style: .cancel) { [weak self] _ in
            self?.viewModel.dismissSuccessDialog()
            self?.navigationController?.popViewController(animated: true)
        })
        present(alert, animated: true)
        viewModel.dismissSuccessDialog()
    }

    private func showRemarkDialog(file: TaskFileItem) {
        if remarkDialog == nil {
            let dialog = TaskFileRemarkDialogView(frame: view.bounds)
            dialog.onCancel = { [weak self] in
                self?.viewModel.hideRemarkDialog()
            }
            dialog.onConfirm = { [weak self] in
                guard let self, let dialog = self.remarkDialog else { return }
                self.viewModel.updateRemarkDialogText(dialog.inputText)
                self.viewModel.saveRemarkDialog()
            }
            remarkDialog = dialog
            view.addSubview(dialog)
            dialog.snp.makeConstraints { make in make.edges.equalToSuperview() }
        }
        remarkDialog?.apply(file: file, text: viewModel.remarkDialogText)
    }

    private func hideRemarkDialog() {
        remarkDialog?.removeFromSuperview()
        remarkDialog = nil
    }

    private func uploadPickedResults(_ results: [PHPickerResult], isImage: Bool) {
        let scenicId = AppStore.shared.currentScenicId
        guard scenicId > 0 else {
            showToast("请先选择景区")
            return
        }
        let totalCount = results.count
        for (index, result) in results.enumerated() {
            let uploadTaskId = UUID().uuidString.replacingOccurrences(of: "-", with: "")
            let placeholder = viewModel.addUploadPlaceholder(
                fileName: "upload_\(uploadTaskId).\(isImage ? "jpg" : "mp4")",
                fileType: isImage ? 2 : 1,
                uploadTaskId: uploadTaskId
            )
            Task {
                do {
                    let payload = try await TaskMediaLoader.load(from: result, isImage: isImage)
                    let fileURL = try await ossUploadService.uploadTaskFile(
                        data: payload.data,
                        fileName: payload.fileName,
                        fileType: isImage ? 2 : 1,
                        scenicId: scenicId
                    ) { [weak self] progress in
                        Task { @MainActor in
                            self?.viewModel.updateUploadProgress(uploadTaskId: uploadTaskId, progress: progress)
                        }
                    }
                    try await taskAPI.registerUploadedFileURL(scenicId: scenicId, fileURL: fileURL, folderId: 0)
                    await MainActor.run {
                        self.viewModel.markUploadSucceeded(
                            uploadTaskId: uploadTaskId,
                            fileURL: fileURL,
                            autoRemarkWhenSingle: totalCount == 1
                        )
                        if totalCount == 1, let fileID = self.viewModel.consumePendingRemarkFileID() {
                            self.viewModel.presentRemarkDialog(for: fileID)
                        }
                    }
                } catch {
                    await MainActor.run {
                        self.viewModel.markUploadFailed(uploadTaskId: uploadTaskId)
                        self.showToast(error.localizedDescription)
                    }
                }
                _ = placeholder
                _ = index
            }
        }
    }
}

extension TaskAddViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        guard !results.isEmpty else { return }
        uploadPickedResults(results, isImage: pickingMediaType == 2)
    }
}

extension TaskAddViewController: UITextViewDelegate {
    func textViewDidBeginEditing(_ textView: UITextView) {
        if textView.textColor == AppColor.textTertiary {
            textView.text = ""
            textView.textColor = AppColor.textPrimary
        }
    }

    func textViewDidEndEditing(_ textView: UITextView) {
        if textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            textView.text = detailsPlaceholder
            textView.textColor = AppColor.textTertiary
            viewModel.updateTaskDetails("")
        }
    }

    func textViewDidChange(_ textView: UITextView) {
        guard textView.textColor != AppColor.textTertiary else { return }
        viewModel.updateTaskDetails(textView.text)
    }
}

/// 从 PHPicker 结果加载上传数据。
enum TaskMediaLoader {
    struct Payload {
        let data: Data
        let fileName: String
    }

    static func load(from result: PHPickerResult, isImage: Bool) async throws -> Payload {
        let provider = result.itemProvider
        if isImage {
            return try await loadImage(from: provider)
        }
        return try await loadVideo(from: provider)
    }

    private static func loadImage(from provider: NSItemProvider) async throws -> Payload {
        try await withCheckedThrowingContinuation { continuation in
            if provider.canLoadObject(ofClass: UIImage.self) {
                provider.loadObject(ofClass: UIImage.self) { object, error in
                    if let error {
                        continuation.resume(throwing: error)
                        return
                    }
                    guard let image = object as? UIImage, let data = image.jpegData(compressionQuality: 0.9) else {
                        continuation.resume(throwing: OSSUploadError.emptyFile)
                        return
                    }
                    continuation.resume(returning: Payload(data: data, fileName: "image_\(UUID().uuidString).jpg"))
                }
                return
            }
            continuation.resume(throwing: OSSUploadError.unsupportedFileType)
        }
    }

    private static func loadVideo(from provider: NSItemProvider) async throws -> Payload {
        let typeIdentifier = UTType.movie.identifier
        return try await withCheckedThrowingContinuation { continuation in
            provider.loadFileRepresentation(forTypeIdentifier: typeIdentifier) { url, error in
                if let error {
                    continuation.resume(throwing: error)
                    return
                }
                guard let url, let data = try? Data(contentsOf: url) else {
                    continuation.resume(throwing: OSSUploadError.emptyFile)
                    return
                }
                let ext = url.pathExtension.isEmpty ? "mp4" : url.pathExtension
                continuation.resume(returning: Payload(data: data, fileName: "video_\(UUID().uuidString).\(ext)"))
            }
        }
    }
}
