import SwiftUI

/// Relink flow for a broken clip: auto-scan granted folders for fingerprint
/// matches, show candidates with thumbnails, and require a visual confirmation
/// before adopting a match.
struct RelinkSheet: View {
    @EnvironmentObject private var library: SourceLibrary
    @Environment(\.dismiss) private var dismiss
    let clip: SourceClip

    @State private var candidates: [RelinkCandidate] = []
    @State private var isScanning = false
    @State private var confirmingCandidate: RelinkCandidate?
    @State private var showingFolderImporter = false

    var body: some View {
        NavigationStack {
            List {
                Section("Missing clip") {
                    HStack(spacing: 12) {
                        thumbnailView(ThumbnailService.load(for: clip.id))
                        VStack(alignment: .leading, spacing: 4) {
                            Text(clip.displayName).font(.headline)
                            Text(fingerprintText(clip.fingerprint))
                                .font(.caption)
                                .foregroundStyle(.secondary)
                        }
                    }
                }
                Section("Matches") {
                    if isScanning {
                        HStack(spacing: 12) {
                            ProgressView()
                            Text("Scanning granted folders…")
                                .foregroundStyle(.secondary)
                        }
                    } else if candidates.isEmpty {
                        Text(library.folders.isEmpty
                             ? "No folders granted yet. Grant access to the folder where this clip now lives."
                             : "No matches found in granted folders.")
                        .foregroundStyle(.secondary)
                    } else {
                        ForEach(candidates) { candidate in
                            Button {
                                confirmingCandidate = candidate
                            } label: {
                                candidateRow(candidate)
                            }
                            .buttonStyle(.plain)
                        }
                    }
                }
                Section {
                    Button {
                        showingFolderImporter = true
                    } label: {
                        Label("Grant another folder…", systemImage: "folder.badge.plus")
                    }
                }
            }
            .navigationTitle("Relink Clip")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Cancel") { dismiss() }
                }
            }
            .fileImporter(
                isPresented: $showingFolderImporter,
                allowedContentTypes: [.folder]
            ) { result in
                if case .success(let url) = result {
                    library.addFolder(url: url)
                    Task { await scan() }
                }
            }
            .task { await scan() }
            .sheet(item: $confirmingCandidate) { candidate in
                ConfirmRelinkView(clip: clip, candidate: candidate) {
                    library.relink(clipID: clip.id, to: candidate)
                    confirmingCandidate = nil
                    dismiss()
                }
            }
        }
    }

    private func scan() async {
        isScanning = true
        candidates = await library.scanForCandidates(for: clip)
        isScanning = false
    }

    private func candidateRow(_ candidate: RelinkCandidate) -> some View {
        HStack(spacing: 12) {
            thumbnailView(candidate.thumbnail)
            VStack(alignment: .leading, spacing: 4) {
                Text(candidate.fileURL.lastPathComponent)
                    .font(.headline)
                    .lineLimit(1)
                Text(fingerprintText(candidate.fingerprint))
                    .font(.caption)
                    .foregroundStyle(.secondary)
                HStack(spacing: 8) {
                    Text(candidate.isStrongMatch ? "Strong match" : "Possible match")
                        .font(.caption2)
                        .padding(.horizontal, 6)
                        .padding(.vertical, 2)
                        .background(candidate.isStrongMatch ? .green.opacity(0.2) : .yellow.opacity(0.3))
                        .clipShape(Capsule())
                    if !candidate.isDurationSufficient {
                        Label("Shorter than original", systemImage: "exclamationmark.triangle.fill")
                            .font(.caption2)
                            .foregroundStyle(.orange)
                    }
                }
            }
            Spacer()
            Image(systemName: "chevron.right")
                .font(.caption)
                .foregroundStyle(.tertiary)
        }
    }

    private func thumbnailView(_ image: UIImage?) -> some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .fill(.quaternary)
            if let image {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            } else {
                Image(systemName: "film")
                    .foregroundStyle(.secondary)
            }
        }
        .frame(width: 64, height: 64)
        .clipShape(RoundedRectangle(cornerRadius: 8))
    }

    private func fingerprintText(_ fingerprint: ClipFingerprint) -> String {
        var parts = [
            Duration.seconds(fingerprint.duration).formatted(.time(pattern: .minuteSecond)),
            "\(fingerprint.pixelWidth)×\(fingerprint.pixelHeight)",
        ]
        if let size = fingerprint.fileSize {
            parts.append(size.formatted(.byteCount(style: .file)))
        }
        return parts.joined(separator: " · ")
    }
}

/// Side-by-side visual confirmation before adopting a match — fingerprints can
/// produce close-but-wrong matches, and a thumbnail catches that at a glance.
struct ConfirmRelinkView: View {
    @Environment(\.dismiss) private var dismiss
    let clip: SourceClip
    let candidate: RelinkCandidate
    var onConfirm: () -> Void

    var body: some View {
        NavigationStack {
            VStack(spacing: 20) {
                HStack(spacing: 16) {
                    labeledThumbnail(ThumbnailService.load(for: clip.id), label: "Original")
                    Image(systemName: "arrow.right")
                        .foregroundStyle(.secondary)
                    labeledThumbnail(candidate.thumbnail, label: "Matched file")
                }
                .padding(.top)

                VStack(alignment: .leading, spacing: 8) {
                    comparisonRow("Original", clip.displayName, clip.fingerprint)
                    Divider()
                    comparisonRow("Matched", candidate.fileURL.lastPathComponent, candidate.fingerprint)
                }
                .padding()
                .background(.quaternary.opacity(0.5))
                .clipShape(RoundedRectangle(cornerRadius: 12))
                .padding(.horizontal)

                if !candidate.isDurationSufficient {
                    Label("This file is shorter than the original clip. Any edits trimming past its end would break.",
                          systemImage: "exclamationmark.triangle.fill")
                    .font(.callout)
                    .foregroundStyle(.orange)
                    .padding(.horizontal)
                }

                Text("If this turns out to be the wrong file, you can undo the relink from the clip's context menu.")
                    .font(.footnote)
                    .foregroundStyle(.secondary)
                    .multilineTextAlignment(.center)
                    .padding(.horizontal)

                Spacer()

                Button {
                    onConfirm()
                } label: {
                    Text("Relink to This File")
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.borderedProminent)
                .padding(.horizontal)
            }
            .navigationTitle("Confirm Relink")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Cancel") { dismiss() }
                }
            }
        }
    }

    private func labeledThumbnail(_ image: UIImage?, label: String) -> some View {
        VStack(spacing: 6) {
            ZStack {
                RoundedRectangle(cornerRadius: 10)
                    .fill(.quaternary)
                if let image {
                    Image(uiImage: image)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                } else {
                    Image(systemName: "film")
                        .foregroundStyle(.secondary)
                }
            }
            .frame(width: 120, height: 120)
            .clipShape(RoundedRectangle(cornerRadius: 10))
            Text(label)
                .font(.caption)
                .foregroundStyle(.secondary)
        }
    }

    private func comparisonRow(_ label: String, _ name: String, _ fingerprint: ClipFingerprint) -> some View {
        VStack(alignment: .leading, spacing: 2) {
            Text(label)
                .font(.caption2)
                .foregroundStyle(.secondary)
            Text(name)
                .font(.subheadline)
                .lineLimit(1)
            Text(detailText(fingerprint))
                .font(.caption)
                .foregroundStyle(.secondary)
        }
    }

    private func detailText(_ fingerprint: ClipFingerprint) -> String {
        var parts = [
            Duration.seconds(fingerprint.duration).formatted(.time(pattern: .minuteSecond)),
            "\(fingerprint.pixelWidth)×\(fingerprint.pixelHeight)",
        ]
        if let size = fingerprint.fileSize {
            parts.append(size.formatted(.byteCount(style: .file)))
        }
        return parts.joined(separator: " · ")
    }
}
