import ForgejoKit
import SwiftUI

struct CommitHistoryView: View {
    let repository: Repository
    @Binding var branch: String
    @State private var authService: AuthenticationService
    @State private var pagination = PaginationState<Commit>()
    @State private var branches: [Branch] = []
    @State private var showBranchPicker = false

    private let repositoryService: RepositoryService?

    init(repository: Repository, branch: Binding<String>, authService: AuthenticationService) {
        self.repository = repository
        _branch = branch
        self.authService = authService
        repositoryService = authService.client.map { RepositoryService(client: $0) }
    }

    private var owner: String {
        repository.owner
    }

    private var repo: String {
        repository.repoName
    }

    var body: some View {
        @Bindable var pagination = pagination
        List {
            if pagination.isLoading, pagination.items.isEmpty {
                LoadingListSection()
            } else if pagination.items.isEmpty {
                ContentUnavailableView {
                    Label("No Commits", systemImage: "clock.arrow.circlepath")
                        .foregroundStyle(.secondary)
                } description: {
                    Text("No commits found on \(branch).")
                }
            } else {
                Section {
                    ForEach(pagination.items) { commit in
                        NavigationLink {
                            CommitDetailView(
                                commit: commit,
                                repository: repository,
                                authService: authService,
                            )
                        } label: {
                            CommitRow(commit: commit)
                        }
                    }

                    if pagination.hasMore {
                        ProgressView()
                            .frame(maxWidth: .infinity)
                            .listRowBackground(Color.clear)
                            .task {
                                await loadMoreCommits()
                            }
                    }
                }
            }
        }
        .listStyle(.insetGrouped)
        .refreshable {
            await reloadCommits(clearItems: true).value
        }
        .task {
            reloadCommits()
            await loadBranches()
        }
        .onChange(of: branch) {
            reloadCommits(clearItems: true)
        }
        .toolbar {
            ToolbarItem(placement: .topBarTrailing) {
                Button {
                    showBranchPicker = true
                } label: {
                    HStack(spacing: 4) {
                        Image(systemName: "arrow.triangle.branch")
                        Text(branch)
                            .lineLimit(1)
                            .frame(maxWidth: 140)
                    }
                    .font(.subheadline.weight(.medium))
                }
                .disabled(branches.isEmpty)
                .accessibilityIdentifier("branch-selector")
            }
        }
        .sheet(isPresented: $showBranchPicker) {
            NavigationStack {
                List(branches) { branchItem in
                    Button {
                        branch = branchItem.name
                        showBranchPicker = false
                    } label: {
                        HStack {
                            Text(branchItem.name)
                            Spacer()
                            if branchItem.name == branch {
                                Image(systemName: "checkmark")
                                    .foregroundStyle(.blue)
                            }
                        }
                    }
                    .accessibilityIdentifier("branch-option-\(branchItem.name)")
                }
                .navigationTitle("Switch Branch")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .cancellationAction) {
                        Button("Cancel") {
                            showBranchPicker = false
                        }
                    }
                }
            }
            .presentationDetents([.medium])
        }
        .errorAlert(message: $pagination.errorMessage, isPresented: $pagination.showError)
    }

    @discardableResult
    private func reloadCommits(clearItems: Bool = false) -> Task<Void, Never> {
        guard let repositoryService else { return Task {} }
        return pagination.reload(clearItems: clearItems) { [self] page, limit in
            try await repositoryService.fetchCommits(
                owner: owner,
                repo: repo,
                sha: branch,
                page: page,
                limit: limit,
            )
        }
    }

    private func loadBranches() async {
        guard let repositoryService else { return }
        do {
            branches = try await repositoryService.fetchBranches(
                owner: owner,
                repo: repo,
            )
        } catch {
            // Non-critical, branch selector stays disabled
        }
    }

    private func loadMoreCommits() async {
        guard let repositoryService else { return }
        await pagination.loadMore { page, limit in
            let fetched = try await repositoryService.fetchCommits(
                owner: owner,
                repo: repo,
                sha: branch,
                page: page,
                limit: limit,
            )
            try Task.checkCancellation()
            return fetched
        }
    }
}

struct CommitRow: View {
    let commit: Commit

    var body: some View {
        VStack(alignment: .leading, spacing: 6) {
            Text(commitTitle)
                .font(.body)
                .lineLimit(2)

            HStack(spacing: 8) {
                if let authorName = displayName {
                    Text(authorName)
                        .fontWeight(.medium)
                }

                Text(shortSHA)
                    .monospaced()

                if let date = commit.commit.committer?.date ?? commit.commit.author?.date {
                    Text(formatRelativeDate(date))
                }
            }
            .font(.caption)
            .foregroundStyle(.secondary)
        }
        .padding(.vertical, 4)
        .accessibilityIdentifier("commit-row-\(commit.sha.prefix(7))")
    }

    private var commitTitle: String {
        let message = commit.commit.message
        return message.components(separatedBy: "\n").first ?? message
    }

    private var shortSHA: String {
        String(commit.sha.prefix(7))
    }

    private var displayName: String? {
        commit.author?.login ?? commit.commit.author?.name
    }
}

#if DEBUG
    #Preview {
        NavigationStack {
            CommitHistoryView(
                repository: .preview,
                branch: .constant("main"),
                authService: .previewDefault,
            )
        }
    }
#endif
