import ForgejoKit
import SwiftUI

struct WorkflowRunDetailView: View {
    let repository: Repository
    let runId: Int
    @State private var authService: AuthenticationService
    @State private var run: WorkflowRun?
    @State private var runView: WorkflowRunView?
    @State private var isLoading = false
    @State private var errorMessage: String?
    @State private var showError = false
    @State private var hasLoaded = false

    private let workflowService: WorkflowService?

    init(repository: Repository, runId: Int, authService: AuthenticationService) {
        self.repository = repository
        self.runId = runId
        self.authService = authService
        workflowService = authService.client.map { WorkflowService(client: $0) }
    }

    var body: some View {
        List {
            if let run {
                headerSection(run: run)
                metadataSection(run: run)
                jobsSection(run: run)
            } else if isLoading {
                LoadingListSection()
            }
        }
        .listStyle(.insetGrouped)
        .navigationTitle(run.map(\.displayName) ?? "Run")
        .navigationBarTitleDisplayMode(.inline)
        .refreshable {
            await loadDetails()
        }
        .task {
            if !hasLoaded {
                await loadDetails()
            }
        }
        .toolbar {
            if let url = run?.htmlUrl, let parsed = URL(string: url) {
                ToolbarItem(placement: .topBarTrailing) {
                    Link(destination: parsed) {
                        Image(systemName: "safari")
                    }
                    .accessibilityLabel("Open in browser")
                    .accessibilityIdentifier("workflow-run-open-browser")
                }
            }
        }
        .errorAlert(message: $errorMessage, isPresented: $showError)
    }

    private func headerSection(run: WorkflowRun) -> some View {
        Section {
            HStack(spacing: 10) {
                WorkflowStatusIcon(status: run.status)
                    .font(.title2)
                VStack(alignment: .leading, spacing: 4) {
                    Text(run.displayName)
                        .font(.headline)
                    Text(run.statusStyle.label)
                        .font(.subheadline)
                        .foregroundStyle(run.statusStyle.tint)
                }
            }

            if let index = run.indexInRepo {
                Label("#\(index)", systemImage: "number")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            if let ref = run.prettyRef {
                Label(ref, systemImage: "arrow.triangle.branch")
                    .font(.subheadline)
            }

            if let sha = run.shortCommitSha {
                Label(sha, systemImage: "number.square")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
    }

    private func metadataSection(run: WorkflowRun) -> some View {
        Section("Details") {
            if let workflow = run.workflowId {
                Label(workflow, systemImage: "doc.text")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            if let event = run.event {
                Label(event, systemImage: "bolt")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            if let actor = run.triggerUser?.login {
                Label("Triggered by \(actor)", systemImage: "person")
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            if let started = run.startedDisplay {
                Label {
                    HStack {
                        Text("Started")
                        Spacer()
                        Text(started, style: .relative)
                            .foregroundStyle(.secondary)
                    }
                } icon: {
                    Image(systemName: "clock")
                }
                .font(.subheadline)
            }

            if let duration = run.duration {
                Label {
                    HStack {
                        Text("Duration")
                        Spacer()
                        Text(formatDuration(duration))
                            .foregroundStyle(.secondary)
                    }
                } icon: {
                    Image(systemName: "stopwatch")
                }
                .font(.subheadline)
            }

            if run.needApproval == true {
                Label("Awaiting approval", systemImage: "hand.raised")
                    .font(.subheadline)
                    .foregroundStyle(.orange)
            }
        }
    }

    @ViewBuilder
    private func jobsSection(run: WorkflowRun) -> some View {
        if let runIndex = run.indexInRepo, let jobs = runView?.state.run.jobs, !jobs.isEmpty {
            Section {
                ForEach(Array(jobs.enumerated()), id: \.element.id) { index, job in
                    NavigationLink {
                        WorkflowJobView(
                            repository: repository,
                            runIndex: runIndex,
                            jobIndex: index,
                            jobName: job.name,
                            authService: authService,
                        )
                    } label: {
                        WorkflowJobSummaryRow(job: job)
                    }
                    .accessibilityIdentifier("workflow-job-\(job.id)")
                }
            } header: {
                HStack {
                    Text("Jobs")
                    Spacer()
                    Text("Experimental")
                        .font(.caption2.weight(.medium))
                        .foregroundStyle(.orange)
                }
            }
        }
    }

    private func loadDetails() async {
        guard let workflowService else { return }
        isLoading = true
        errorMessage = nil

        do {
            run = try await workflowService.fetchRun(
                owner: repository.owner,
                repo: repository.repoName,
                runId: runId,
            )
            hasLoaded = true
        } catch is CancellationError {
            // Ignore cancellation
        } catch {
            errorMessage = error.localizedDescription
            showError = true
        }

        isLoading = false

        // Best-effort experimental fetch, don't surface errors if it fails
        // (e.g. older Forgejo versions without this route, or auth quirks).
        if let runIndex = run?.indexInRepo {
            await loadRunView(runIndex: runIndex)
        }
    }

    private func loadRunView(runIndex: Int) async {
        guard let workflowService else { return }
        do {
            runView = try await workflowService.fetchRunView(
                owner: repository.owner,
                repo: repository.repoName,
                runIndex: runIndex,
                jobIndex: 0,
                logCursors: [],
            )
        } catch {
            // Silent, experimental endpoint failure shouldn't block run detail.
        }
    }

    private func formatDuration(_ seconds: TimeInterval) -> String {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.hour, .minute, .second]
        formatter.unitsStyle = .abbreviated
        return formatter.string(from: seconds) ?? "-"
    }
}

private struct WorkflowJobSummaryRow: View {
    let job: WorkflowRunViewJob

    var body: some View {
        HStack(spacing: 10) {
            WorkflowStatusIcon(status: job.status)
            VStack(alignment: .leading, spacing: 2) {
                Text(job.name)
                    .font(.subheadline)
                if !job.duration.isEmpty {
                    Text(job.duration)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
        }
        .padding(.vertical, 2)
    }
}
