import AppKit
import Foundation
import UniformTypeIdentifiers

@MainActor
final class MaterialStore: ObservableObject {
    @Published var textures: [TextureSlotKind: TextureAsset] = [:]
    @Published var settings = ConversionSettings()
    @Published var previews: [OutputPreviewKind: NSImage] = [:]
    @Published var logLines: [String] = [
        "Load Base Color first, then add Normal, AO, Roughness/Gloss and Metallic as needed."
    ]
    @Published var lastExportURL: URL?

    private let processor = TextureProcessor()

    var canExport: Bool {
        textures[.baseColor] != nil
    }

    var hasAnyTexture: Bool {
        !textures.isEmpty
    }

    func chooseTexture(for kind: TextureSlotKind) {
        let panel = NSOpenPanel()
        panel.title = "Choose \(kind.title) Texture"
        panel.prompt = "Use Texture"
        panel.allowsMultipleSelection = false
        panel.canChooseDirectories = false
        panel.canChooseFiles = true
        panel.allowedContentTypes = [.png, .jpeg, .tiff, .bmp, .gif, .heic]

        if panel.runModal() == .OK, let url = panel.url {
            importTexture(url, for: kind)
        }
    }

    func importTexture(_ url: URL, for kind: TextureSlotKind) {
        do {
            let asset = try processor.loadAsset(from: url)
            textures[kind] = asset

            if kind == .baseColor, settings.materialName == "BREDA_PBR_Material" {
                settings.materialName = url.deletingPathExtension().lastPathComponent
            }

            appendLog("\(kind.title) loaded: \(asset.fileName), \(asset.sizeLabel)")
            buildPreview()
        } catch {
            appendLog("Load failed: \(error.localizedDescription)")
        }
    }

    func removeTexture(_ kind: TextureSlotKind) {
        textures.removeValue(forKey: kind)
        previews.removeAll()
        appendLog("\(kind.title) removed.")
        if hasAnyTexture {
            buildPreview()
        }
    }

    func reset() {
        textures.removeAll()
        previews.removeAll()
        lastExportURL = nil
        settings = ConversionSettings()
        logLines = ["Inputs cleared."]
    }

    func buildPreview() {
        do {
            previews = try processor.buildPreviews(textures: textures, settings: settings)
            if !previews.isEmpty {
                appendLog("Preview updated.")
            }
        } catch {
            appendLog("Preview failed: \(error.localizedDescription)")
        }
    }

    func exportMaterialSet() {
        guard canExport else {
            appendLog("Export blocked: Base Color is required.")
            return
        }

        let panel = NSOpenPanel()
        panel.title = "Choose Export Folder"
        panel.prompt = "Export Here"
        panel.canChooseFiles = false
        panel.canChooseDirectories = true
        panel.canCreateDirectories = true
        panel.allowsMultipleSelection = false

        guard panel.runModal() == .OK, let directoryURL = panel.url else {
            return
        }

        do {
            let result = try processor.exportMaterialSet(
                textures: textures,
                settings: settings,
                parentDirectory: directoryURL
            )
            lastExportURL = result.folderURL
            appendLog("Export complete: \(result.folderURL.path)")
            result.files.forEach { appendLog("Wrote \($0)") }
        } catch {
            appendLog("Export failed: \(error.localizedDescription)")
        }
    }

    func acceptDrop(_ providers: [NSItemProvider], for kind: TextureSlotKind) -> Bool {
        guard let provider = providers.first(where: { $0.hasItemConformingToTypeIdentifier(UTType.fileURL.identifier) }) else {
            return false
        }

        provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { [weak self] item, _ in
            let url: URL?
            if let droppedURL = item as? URL {
                url = droppedURL
            } else if let data = item as? Data {
                url = URL(dataRepresentation: data, relativeTo: nil)
            } else {
                url = nil
            }

            guard let url else {
                return
            }

            Task { @MainActor in
                self?.importTexture(url, for: kind)
            }
        }

        return true
    }

    private func appendLog(_ line: String) {
        let timestamp = Self.timestampFormatter.string(from: Date())
        logLines.insert("[\(timestamp)] \(line)", at: 0)
        if logLines.count > 80 {
            logLines.removeLast(logLines.count - 80)
        }
    }

    private static let timestampFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "HH:mm:ss"
        return formatter
    }()
}
