import ForgejoKit
import SwiftUI

struct IssueCreateView: View {
    let repository: Repository
    @State private var authService: AuthenticationService
    @State private var title = ""
    @State private var bodyText = ""
    @State private var isSubmitting = false
    @State private var errorMessage: String?
    @State private var showError = false
    @State private var availableLabels: [IssueLabel] = []
    @State private var availableMilestones: [IssueMilestone] = []
    @State private var availableAssignees: [User] = []
    @State private var selectedLabelIDs: Set<Int> = []
    @State private var selectedMilestoneID: Int?
    @State private var selectedAssigneeLogins: Set<String> = []
    @Environment(\.dismiss) private var dismiss

    private let issueService: IssueService?
    private let repositoryService: RepositoryService?
    private let onCreated: () -> Void
    private let embeddedInNavigation: Bool

    init(
        repository: Repository,
        authService: AuthenticationService,
        embeddedInNavigation: Bool = false,
        onCreated: @escaping () -> Void,
    ) {
        self.repository = repository
        self.authService = authService
        issueService = authService.client.map { IssueService(client: $0) }
        repositoryService = authService.client.map { RepositoryService(client: $0) }
        self.onCreated = onCreated
        self.embeddedInNavigation = embeddedInNavigation
    }

    private var owner: String {
        repository.owner
    }

    private var repo: String {
        repository.repoName
    }

    var body: some View {
        if embeddedInNavigation {
            formContent
        } else {
            NavigationStack {
                formContent
            }
        }
    }

    private var formContent: some View {
        Form {
            Section {
                TextField("Title", text: $title)
                    .accessibilityIdentifier("issue-create-title-field")
            }

            DescriptionEditorSection(text: $bodyText)

            LabelPickerSection(
                availableLabels: availableLabels,
                selectedLabelIDs: $selectedLabelIDs,
            )
            MilestonePickerSection(
                availableMilestones: availableMilestones,
                selectedMilestoneID: $selectedMilestoneID,
            )
            UserPickerSection(
                title: "Assignees",
                availableUsers: availableAssignees,
                selectedLogins: $selectedAssigneeLogins,
            )
        }
        .navigationTitle("New Issue")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .cancellationAction) {
                Button("Cancel") { dismiss() }
            }
            ToolbarItem(placement: .confirmationAction) {
                Button("Create") {
                    Task { await createIssue() }
                }
                .disabled(title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isSubmitting)
                .accessibilityIdentifier("issue-create-submit")
            }
        }
        .errorAlert(message: $errorMessage, isPresented: $showError)
        .task {
            await loadMetadata()
        }
    }

    private func loadMetadata() async {
        guard let repositoryService else { return }
        let metadata = await loadRepositoryMetadata(service: repositoryService, owner: owner, repo: repo)
        availableLabels = metadata.labels
        availableMilestones = metadata.milestones
        availableAssignees = metadata.assignees
    }

    private func createIssue() async {
        guard let issueService else { return }
        isSubmitting = true
        do {
            _ = try await issueService.createIssue(
                owner: owner,
                repo: repo,
                title: title.trimmingCharacters(in: .whitespacesAndNewlines),
                body: bodyText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
                    ? nil : bodyText.trimmingCharacters(in: .whitespacesAndNewlines),
                labels: selectedLabelIDs.isEmpty ? nil : Array(selectedLabelIDs),
                milestone: selectedMilestoneID,
                assignees: selectedAssigneeLogins.isEmpty ? nil : Array(selectedAssigneeLogins),
            )
            NotificationCenter.default.post(name: .issuesDidChange, object: nil)
            onCreated()
            dismiss()
        } catch {
            errorMessage = error.localizedDescription
            showError = true
        }
        isSubmitting = false
    }

    #if DEBUG
        init(preview _: Void, repository: Repository, authService: AuthenticationService,
             availableLabels: [IssueLabel] = [], availableMilestones: [IssueMilestone] = [],
             availableAssignees: [User] = [])
        {
            self.repository = repository
            self.authService = authService
            issueService = nil
            repositoryService = nil
            onCreated = {}
            embeddedInNavigation = false
            _availableLabels = State(initialValue: availableLabels)
            _availableMilestones = State(initialValue: availableMilestones)
            _availableAssignees = State(initialValue: availableAssignees)
        }
    #endif
}

#if DEBUG
    #Preview {
        NavigationStack {
            IssueCreateView(
                preview: (),
                repository: .preview,
                authService: .previewDefault,
                availableLabels: IssueLabel.previewList,
                availableMilestones: [.preview],
                availableAssignees: [.preview, .previewBot],
            )
        }
    }
#endif
