import SwiftUI
import UniformTypeIdentifiers

// MARK: - Root View

struct ContentView: View {
    @StateObject private var vm: ExtractionViewModel
    @State private var showDestinationPicker = false

    @MainActor
    init(vm: ExtractionViewModel? = nil) {
        _vm = StateObject(wrappedValue: vm ?? ExtractionViewModel())
    }

    var body: some View {
        HSplitView {
            // Left panel: drop zone + group list
            // leftPanel
            //     .frame(minWidth: 260, idealWidth: 300, maxWidth: 360)
          leftPanel
                .frame(minWidth: 260)

            // Right panel: selected group detail + controls
            rightPanel
                .frame(minWidth: 400)
        }
        .frame(minWidth: 720, minHeight: 520)
        .background(Color(NSColor.windowBackgroundColor))
        .fileImporter(
            isPresented: $showDestinationPicker,
            allowedContentTypes: [.folder],
            allowsMultipleSelection: false
        ) { result in
            if case .success(let urls) = result, let url = urls.first {
                vm.destinationURL = url
            }
        }
    }

    // MARK: - Left Panel

    private var leftPanel: some View {
        VStack(spacing: 0) {
            dropZone
            Divider()
            // groupList
        }
    }

    private var dropZone: some View {
        DropZoneView { urls in
            vm.handleDrop(of: urls)
        }
        // .frame(height: 240)
        .padding(12)
    }

    // private var groupList: some View {
    //     Group {
    //         if vm.groups.isEmpty {
    //             VStack(spacing: 8) {
    //                 Text("No files yet")
    //                     .font(.callout)
    //                     .foregroundStyle(.secondary)
    //             }
    //             .frame(maxWidth: .infinity, maxHeight: .infinity)
    //         } else {
    //             List(vm.groups, selection: $vm.selectedGroup) { group in
    //                 GroupRow(group: group, isSelected: vm.selectedGroup?.id == group.id)
    //                     .tag(group)
    //                     .contextMenu {
    //                         Button("Remove", role: .destructive) {
    //                             vm.removeGroup(group)
    //                         }
    //                     }
    //             }
    //             .listStyle(.sidebar)
    //         }
    //     }
    // }

    // MARK: - Right Panel

    private var rightPanel: some View {
        VStack(alignment: .leading, spacing: 0) {
            if let group = vm.selectedGroup {
                detailHeader(group: group)
                Divider()
                fileListSection(group: group)
                Divider()
                controlsSection
                Divider()
                consoleSection
            } else {
                emptyDetail
            }
        }
    }

    private func detailHeader(group: ZipFileGroup) -> some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(group.baseName)
                .font(.title3.weight(.semibold))
            Text("\(group.files.count) part\(group.files.count == 1 ? "" : "s") · \(totalSize(group.files))")
                .font(.caption)
                .foregroundStyle(.secondary)

            if let warning = group.warningMessage {
                Label(warning, systemImage: "exclamationmark.triangle.fill")
                    .font(.caption)
                    .foregroundStyle(.orange)
                    .padding(.top, 2)
            }
        }
        .padding(.horizontal, 20)
        .padding(.vertical, 14)
    }

    private func fileListSection(group: ZipFileGroup) -> some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 0) {
                ForEach(Array(group.files.enumerated()), id: \.offset) { index, url in
                    FileRow(url: url, index: index)
                    if index < group.files.count - 1 {
                        Divider().padding(.leading, 44)
                    }
                }
            }
            .padding(.vertical, 4)
        }
        .frame(maxHeight: 220)
    }

    private var controlsSection: some View {
        HStack(spacing: 12) {
            // Destination picker
            VStack(alignment: .leading, spacing: 4) {
                Text("Destination")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Button {
                    showDestinationPicker = true
                } label: {
                    HStack(spacing: 6) {
                        Image(systemName: "folder")
                        Text(vm.destinationURL?.lastPathComponent ?? "Choose folder…")
                            .lineLimit(1)
                            .truncationMode(.middle)
                    }
                }
                .buttonStyle(.bordered)
                .controlSize(.small)
            }

            Spacer()

            // Progress + start button
            VStack(alignment: .trailing, spacing: 8) {
                if vm.state.isActive || vm.state == .succeeded {
                    ProgressView(value: vm.progress)
                        .frame(width: 180)
                        .animation(.easeInOut(duration: 0.3), value: vm.progress)
                }

                HStack(spacing: 10) {
                    if case .failed(_) = vm.state {
                        Label("Failed", systemImage: "xmark.circle.fill")
                            .foregroundStyle(.red)
                            .font(.callout.weight(.medium))
                    } else if vm.state == .succeeded {
                        Label("Done", systemImage: "checkmark.circle.fill")
                            .foregroundStyle(.green)
                            .font(.callout.weight(.medium))
                    }

                    Button {
                        if vm.state == .succeeded || vm.state == .failed("") {
                            vm.clearAll()
                        } else {
                            vm.startExtraction()
                        }
                    } label: {
                        Label(
                            vm.state == .succeeded ? "Clear" : (vm.state.isActive ? "Running…" : "Start Extraction"),
                            systemImage: vm.state == .succeeded ? "arrow.counterclockwise" : "archivebox"
                        )
                        .frame(minWidth: 140)
                    }
                    .buttonStyle(.borderedProminent)
                    .controlSize(.large)
                    .disabled(!vm.canStart && vm.state != .succeeded)
                    .keyboardShortcut(.return, modifiers: .command)
                }
            }
        }
        .padding(.horizontal, 20)
        .padding(.vertical, 14)
    }

    private var consoleSection: some View {
        VStack(alignment: .leading, spacing: 0) {
            HStack {
                Text("Console")
                    .font(.caption.weight(.semibold))
                    .foregroundStyle(.secondary)
                Spacer()
                if !vm.consoleOutput.isEmpty {
                    Button("Clear") { vm.consoleOutput = "" }
                        .font(.caption)
                        .buttonStyle(.plain)
                        .foregroundStyle(.secondary)
                }
            }
            .padding(.horizontal, 14)
            .padding(.top, 10)
            .padding(.bottom, 6)

            ScrollViewReader { proxy in
                ScrollView {
                    Text(vm.consoleOutput.isEmpty ? "Output will appear here." : vm.consoleOutput)
                        .font(.system(.caption, design: .monospaced))
                        .foregroundStyle(vm.consoleOutput.isEmpty ? Color.secondary : Color.primary)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding(12)
                        .id("bottom")
                }
                .background(Color(NSColor.textBackgroundColor).opacity(0.4))
                .onChange(of: vm.consoleOutput) { _ in
                    withAnimation {
                        proxy.scrollTo("bottom", anchor: .bottom)
                    }
                }
            }
        }
    }

    private var emptyDetail: some View {
        VStack(spacing: 12) {
            Image(systemName: "doc.zipper")
                .font(.system(size: 48))
                .foregroundStyle(.quaternary)
            Text("Drop split .zip files to get started")
                .font(.callout)
                .foregroundStyle(.tertiary)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

    // MARK: - Helpers

    private func totalSize(_ urls: [URL]) -> String {
        let bytes = urls.compactMap {
            try? FileManager.default.attributesOfItem(atPath: $0.path)[.size] as? Int64
        }.reduce(0, +)
        return ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file)
    }
}

// MARK: - Drop Zone View

struct DropZoneView: View {
    let onDrop: ([URL]) -> Void

    @State private var isTargeted = false

    var body: some View {
        RoundedRectangle(cornerRadius: 12, style: .continuous)
            .strokeBorder(
                isTargeted ? Color.accentColor : Color.secondary.opacity(0.35),
                style: StrokeStyle(lineWidth: 2, dash: [6, 4])
            )
            .background(
                RoundedRectangle(cornerRadius: 12, style: .continuous)
                    .fill(isTargeted ? Color.accentColor.opacity(0.08) : Color.clear)
            )
            .overlay {
                VStack(spacing: 8) {
                    Image(systemName: isTargeted ? "arrow.down.circle.fill" : "arrow.down.circle")
                        .font(.system(size: 28))
                        .foregroundStyle(isTargeted ? Color.accentColor : .secondary)
                        .animation(.spring(response: 0.3), value: isTargeted)
                    Text("Drop .zip parts here")
                        .font(.callout.weight(.medium))
                        .foregroundStyle(isTargeted ? Color.accentColor : .secondary)
                    Text("e.g. archive.zip, archive(1).zip, …")
                        .font(.caption)
                        .foregroundStyle(.tertiary)
                }
            }
            .animation(.easeInOut(duration: 0.2), value: isTargeted)
            .onDrop(of: [UTType.fileURL], isTargeted: $isTargeted) { providers in
                var resolved: [URL] = []
                let group = DispatchGroup()

                for provider in providers {
                    group.enter()
                    provider.loadItem(forTypeIdentifier: UTType.fileURL.identifier, options: nil) { item, _ in
                        defer { group.leave() }
                        guard let data = item as? Data,
                              let url = URL(dataRepresentation: data, relativeTo: nil) else { return }
                        resolved.append(url)
                    }
                }

                group.notify(queue: .main) {
                    onDrop(resolved)
                }
                return true
            }
    }
}

// MARK: - Group Row

struct GroupRow: View {
    let group: ZipFileGroup
    let isSelected: Bool

    var body: some View {
        HStack(spacing: 10) {
            Image(systemName: group.isMissingParts ? "exclamationmark.triangle" : "archivebox")
                .foregroundStyle(group.isMissingParts ? .orange : .secondary)
                .frame(width: 18)

            VStack(alignment: .leading, spacing: 2) {
                Text(group.baseName)
                    .font(.callout.weight(.medium))
                    .lineLimit(1)
                Text("\(group.files.count) part\(group.files.count == 1 ? "" : "s")")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
        }
        .padding(.vertical, 4)
    }
}

// MARK: - File Row

struct FileRow: View {
    let url: URL
    let index: Int

    var body: some View {
        HStack(spacing: 12) {
            Text("\(index + 1)")
                .font(.system(.caption, design: .monospaced))
                .foregroundStyle(.tertiary)
                .frame(width: 20, alignment: .trailing)

            Image(systemName: "doc.zipper")
                .foregroundStyle(.secondary)
                .frame(width: 16)
            
            Image(systemName: "trash").contentTransition(.symbolEffect(.replace.magic(fallback: .downUp.wholeSymbol), options: .nonRepeating))

            VStack(alignment: .leading, spacing: 2) {
                Text(url.lastPathComponent)
                    .font(.callout)
                    .lineLimit(1)
                Text(url.deletingLastPathComponent().path)
                    .font(.caption)
                    .foregroundStyle(.tertiary)
                    .lineLimit(1)
                    .truncationMode(.middle)
            }

            Spacer()

            if let size = fileSize(url) {
                Text(size)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
    }

    private func fileSize(_ url: URL) -> String? {
        guard let bytes = try? FileManager.default
            .attributesOfItem(atPath: url.path)[.size] as? Int64 else { return nil }
        return ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file)
    }
}

// MARK: - Preview

#Preview {
    let vm = ExtractionViewModel()
    let mockGroup = ZipFileGroup(
        baseName: "Photos",
        files: [
            URL(fileURLWithPath: "/Users/ghassan/Desktop/ZipMerger/DriveZipMerger/MockZIPs/Photos.zip"),
            URL(fileURLWithPath: "/Users/ghassan/Desktop/ZipMerger/DriveZipMerger/MockZIPs/Photos(1).zip"),
            URL(fileURLWithPath: "/Users/ghassan/Desktop/ZipMerger/DriveZipMerger/MockZIPs/Photos(2).zip")
        ],
        isMissingParts: false,
        missingIndices: []
    )
    vm.groups = [mockGroup]
    vm.selectedGroup = mockGroup
    vm.destinationURL = URL(fileURLWithPath: "/Users/ghassan/Downloads")
    vm.state = .running
    vm.progress = 0.65
    vm.consoleOutput = """
    ▶ Merging 3 part(s) into combined archive...
    [1/3] Merging Photos.zip...
    [2/3] Merging Photos(1).zip...
    [3/3] Merging Photos(2).zip...
    ✔ Merge complete.
    ▶ Unzipping into /Users/ghassan/Downloads...
    inflating: Photos/image1.jpg
    inflating: Photos/image2.jpg
    """
    
    return ContentView(vm: vm)
        .frame(width: 800, height: 560)
}
