import SwiftUI

struct AddSourceView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject var iapService: IAPService
    @EnvironmentObject var accountStore: AccountStore

    @State private var name = ""
    @State private var selectedCategory: Category?
    @State private var initialValue = ""
    @State private var showingCategoryPicker = false
    @State private var selectedAccountId: UUID?
    @State private var duplicateError: String?

    @StateObject private var categoryRepository = CategoryRepository()
    @StateObject private var sourceRepository = InvestmentSourceRepository()

    private var availableAccounts: [Account] {
        accountStore.accounts.filter { $0.safeId != nil }
    }

    var body: some View {
        NavigationStack {
            Form {
                if availableAccounts.count > 1 {
                    Section {
                        Picker("Account", selection: $selectedAccountId) {
                            ForEach(availableAccounts, id: \.objectID) { account in
                                Text(account.name).tag(Optional(account.safeId))
                            }
                        }
                        .onChange(of: selectedAccountId) { _, _ in
                            validateSourceName(name)
                        }
                    } header: {
                        Text("Account")
                    }
                }

                // Source Info
                Section {
                    TextField(String(localized: "add_source_name_placeholder"), text: $name)
                        .textContentType(.organizationName)
                        .onChange(of: name) { _, newValue in
                            validateSourceName(newValue)
                        }

                    Button {
                        showingCategoryPicker = true
                    } label: {
                        HStack {
                            Text("Category")
                                .foregroundColor(.primary)

                            Spacer()

                            if let category = selectedCategory {
                                HStack(spacing: 6) {
                                    Image(systemName: category.icon)
                                        .foregroundColor(category.color)
                                    Text(category.name)
                                        .foregroundColor(.secondary)
                                }
                            } else {
                                Text("Select")
                                    .foregroundColor(.secondary)
                            }

                            Image(systemName: "chevron.right")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }
                } header: {
                    Text("Source Information")
                } footer: {
                    if let error = duplicateError {
                        Text(error)
                            .foregroundColor(.negativeRed)
                    } else {
                        Text(String(localized: "add_source_name_footer"))
                            .foregroundColor(.secondary)
                    }
                }

                // Initial Value (Optional)
                Section {
                    HStack {
                        Text(currencySymbol)
                            .foregroundColor(.secondary)

                        TextField("0.00", text: $initialValue)
                            .keyboardType(.decimalPad)
                    }
                } header: {
                    Text("Initial Value (Optional)")
                } footer: {
                    Text("You can add snapshots later if you prefer.")
                }
            }
            .navigationTitle("Add Source")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Add") {
                        saveSource()
                    }
                    .disabled(!isValid)
                    .fontWeight(.semibold)
                }
            }
            .sheet(isPresented: $showingCategoryPicker) {
                CategoryPickerView(
                    selectedCategory: $selectedCategory,
                    categories: categoryRepository.categories
                )
            }
            .onAppear {
                categoryRepository.createDefaultCategoriesIfNeeded()
                if selectedCategory == nil {
                    selectedCategory = categoryRepository.categories.first
                }
                if selectedAccountId == nil {
                    selectedAccountId = accountStore.selectedAccount?.safeId ?? availableAccounts.first?.safeId
                }
            }
        }
    }

    // MARK: - Validation

    private var isValid: Bool {
        !name.trimmingCharacters(in: .whitespaces).isEmpty && selectedCategory != nil && duplicateError == nil
    }

    private func validateSourceName(_ newName: String) {
        let trimmed = newName.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else {
            duplicateError = nil
            return
        }

        if sourceRepository.sourceExists(name: trimmed, in: selectedAccount) {
            duplicateError = "A source with this name already exists."
        } else {
            duplicateError = nil
        }
    }

    // MARK: - Save

    private func saveSource() {
        guard let category = selectedCategory else { return }

        let repository = InvestmentSourceRepository()
        let source = repository.createSource(
            name: name.trimmingCharacters(in: .whitespaces),
            category: category,
            account: selectedAccount
        )

        // Add initial snapshot if provided
        if let value = parseDecimal(initialValue), value > 0 {
            let snapshotRepository = SnapshotRepository()
            snapshotRepository.createSnapshot(
                for: source,
                date: Date(),
                value: value
            )
        }

        // Schedule notification
        NotificationService.shared.scheduleReminder(for: source)

        // Check milestone after snapshot is saved
        let sourceRepo = InvestmentSourceRepository()
        let allSources = sourceRepo.fetchActiveSources()
        let total = allSources.reduce(Decimal.zero) { $0 + $1.latestValue }
        NotificationService.shared.checkAndScheduleMilestoneNotification(portfolioValue: total)

        // Log analytics
        FirebaseService.shared.logSourceAdded(
            categoryName: category.name,
            sourceCount: repository.sourceCount
        )

        dismiss()
    }

    private func parseDecimal(_ string: String) -> Decimal? {
        CurrencyFormatter.parseUserInput(string, currencySymbol: currencySymbol)
    }

    private var currencySymbol: String {
        if let account = selectedAccount, let code = account.currencyCode {
            return CurrencyFormatter.symbol(for: code)
        }
        return AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currencySymbol
    }

    private var currencyCode: String {
        if let account = selectedAccount, let code = account.currencyCode {
            return code
        }
        return AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
    }

    private var selectedAccount: Account? {
        guard let id = selectedAccountId else { return nil }
        return availableAccounts.first { $0.safeId == id }
    }
}

// MARK: - Category Picker View

struct CategoryPickerView: View {
    @Environment(\.dismiss) private var dismiss
    @Binding var selectedCategory: Category?
    let categories: [Category]

    var body: some View {
        NavigationStack {
            List(categories) { category in
                Button {
                    selectedCategory = category
                    dismiss()
                } label: {
                    HStack(spacing: 12) {
                        ZStack {
                            Circle()
                                .fill(category.color.opacity(0.2))
                                .frame(width: 40, height: 40)

                            Image(systemName: category.icon)
                                .foregroundColor(category.color)
                        }

                        Text(category.name)
                            .foregroundColor(.primary)

                        Spacer()

                        if selectedCategory?.id == category.id {
                            Image(systemName: "checkmark")
                                .foregroundColor(.appPrimary)
                        }
                    }
                }
            }
            .navigationTitle("Select Category")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Done") {
                        dismiss()
                    }
                }
            }
        }
    }
}

// MARK: - Edit Source View

struct EditSourceView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject var accountStore: AccountStore
    let source: InvestmentSource

    @State private var name: String
    @State private var selectedCategory: Category?
    @State private var showingCategoryPicker = false
    @State private var selectedAccountId: UUID?

    @StateObject private var categoryRepository = CategoryRepository()

    init(source: InvestmentSource) {
        self.source = source
        _name = State(initialValue: source.name)
        _selectedCategory = State(initialValue: source.category)
        _selectedAccountId = State(initialValue: source.account?.safeId)
    }

    var body: some View {
        NavigationStack {
            Form {
                if availableAccounts.count > 1 {
                    Section {
                        Picker("Account", selection: $selectedAccountId) {
                            ForEach(availableAccounts, id: \.objectID) { account in
                                Text(account.name).tag(Optional(account.safeId))
                            }
                        }
                    } header: {
                        Text("Account")
                    }
                }

                Section {
                    TextField("Source Name", text: $name)

                    Button {
                        showingCategoryPicker = true
                    } label: {
                        HStack {
                            Text("Category")
                                .foregroundColor(.primary)

                            Spacer()

                            if let category = selectedCategory {
                                HStack(spacing: 6) {
                                    Image(systemName: category.icon)
                                        .foregroundColor(category.color)
                                    Text(category.name)
                                        .foregroundColor(.secondary)
                                }
                            }

                            Image(systemName: "chevron.right")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }
                }
            }
            .navigationTitle("Edit Source")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") {
                        saveChanges()
                    }
                    .disabled(!isValid)
                    .fontWeight(.semibold)
                }
            }
            .sheet(isPresented: $showingCategoryPicker) {
                CategoryPickerView(
                    selectedCategory: $selectedCategory,
                    categories: categoryRepository.categories
                )
            }
        }
    }

    private var availableAccounts: [Account] {
        accountStore.accounts.filter { $0.safeId != nil }
    }

    private var isValid: Bool {
        !name.trimmingCharacters(in: .whitespaces).isEmpty && selectedCategory != nil
    }

    private func saveChanges() {
        guard let category = selectedCategory else { return }

        let repository = InvestmentSourceRepository()
        repository.updateSource(
            source,
            name: name.trimmingCharacters(in: .whitespaces),
            category: category,
            account: selectedAccount
        )

        // Reschedule notification
        NotificationService.shared.scheduleReminder(for: source)

        dismiss()
    }

    private var selectedAccount: Account? {
        guard let id = selectedAccountId else { return nil }
        return availableAccounts.first { $0.safeId == id }
    }
}

// MARK: - Add Snapshot View

struct AddSnapshotView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.scenePhase) private var scenePhase
    let source: InvestmentSource
    let snapshot: Snapshot?

    @StateObject private var viewModel: SnapshotFormViewModel
    @State private var showingDuplicateAlert = false
    @State private var showingPropagationDialog = false
    @State private var pendingContribution: Decimal?

    init(source: InvestmentSource, snapshot: Snapshot? = nil) {
        self.source = source
        self.snapshot = snapshot
        if let snapshot = snapshot {
            _viewModel = StateObject(wrappedValue: SnapshotFormViewModel(source: source, mode: .edit(snapshot)))
        } else {
            _viewModel = StateObject(wrappedValue: SnapshotFormViewModel(source: source))
        }
    }

    var body: some View {
        NavigationStack {
            Form {
                Section {
                    if snapshot == nil && viewModel.previousValue != nil {
                        Button {
                            viewModel.prefillFromPreviousSnapshot()
                        } label: {
                            Label("Duplicate Previous Snapshot", systemImage: "doc.on.doc")
                        }
                    }

                    DatePicker(
                        "Date",
                        selection: $viewModel.date,
                        in: ...Date(),
                        displayedComponents: .date
                    )

                    HStack {
                        Text(viewModel.currencySymbol)
                            .foregroundColor(.secondary)

                        TextField("Value", text: $viewModel.valueString)
                            .keyboardType(.decimalPad)
                    }

                    if let clipboardValue = viewModel.clipboardValue {
                        Button {
                            viewModel.applyClipboardValue()
                        } label: {
                            Label("Paste \(clipboardValue) from clipboard", systemImage: "doc.on.clipboard")
                        }
                        .tint(.appPrimary)
                    }

                    if viewModel.previousValue != nil {
                        Text(viewModel.previousValueString)
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                } header: {
                    Text("Snapshot Details")
                }

                // Change preview
                if let change = viewModel.formattedChange,
                   let percentage = viewModel.formattedChangePercentage {
                    Section {
                        HStack {
                            Text("Change from previous")
                            Spacer()
                            Text("\(change) (\(percentage))")
                                .foregroundColor(
                                    (viewModel.changeFromPrevious ?? 0) >= 0
                                        ? .positiveGreen
                                        : .negativeRed
                                )
                        }
                    }
                }

                Section {
                    Toggle("Include Contribution", isOn: $viewModel.includeContribution)

                    if viewModel.includeContribution {
                        HStack {
                            Text(viewModel.currencySymbol)
                                .foregroundColor(.secondary)

                            TextField("New capital added", text: $viewModel.contributionString)
                                .keyboardType(.decimalPad)
                        }
                    }
                } header: {
                    Text("Contribution (Optional)")
                } footer: {
                    Text("Track new capital added to separate it from investment growth.")
                }

                Section {
                    TextField("Notes", text: $viewModel.notes, axis: .vertical)
                        .lineLimit(3...6)
                } header: {
                    Text("Notes (Optional)")
                }
            }
            .navigationTitle(viewModel.title)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(viewModel.buttonTitle) {
                        saveSnapshot()
                    }
                    .disabled(!viewModel.isValid)
                    .fontWeight(.semibold)
                }
            }
            .onAppear {
                viewModel.checkClipboard()
            }
            .onChange(of: scenePhase) { _, phase in
                if phase == .active {
                    viewModel.checkClipboard()
                }
            }
            .alert(
                String(localized: "snapshot_duplicate_title"),
                isPresented: $showingDuplicateAlert
            ) {
                Button(String(localized: "snapshot_duplicate_replace"), role: .destructive) {
                    performSave()
                }
                Button(String(localized: "snapshot_duplicate_add")) {
                    performSave()
                }
                Button("Cancel", role: .cancel) {}
            } message: {
                Text(String(localized: "snapshot_duplicate_message"))
            }
            .confirmationDialog(
                String(localized: "snapshot_contribution_propagate_title"),
                isPresented: $showingPropagationDialog,
                titleVisibility: .visible
            ) {
                Button(String(localized: "snapshot_contribution_propagate_forward")) { propagate(.forward) }
                Button(String(localized: "snapshot_contribution_propagate_backward")) { propagate(.backward) }
                Button(String(localized: "snapshot_contribution_propagate_all")) { propagate(.all) }
                Button(String(localized: "snapshot_contribution_propagate_this"), role: .cancel) { dismiss() }
            } message: {
                if let amount = pendingContribution {
                    Text(String(format: String(localized: "snapshot_contribution_propagate_message"), amount.currencyString))
                }
            }
        }
    }

    private func saveSnapshot() {
        guard snapshot == nil else {
            performSave()
            return
        }

        // Check for existing snapshot in the same month
        let calendar = Calendar.current
        let selectedMonth = calendar.dateComponents([.year, .month], from: viewModel.date)
        let repo = SnapshotRepository()
        let existing = repo.fetchSnapshots(for: source, limitedToMonths: nil)
        let hasDuplicate = existing.contains { snap in
            let snapMonth = calendar.dateComponents([.year, .month], from: snap.date)
            return snapMonth == selectedMonth
        }

        if hasDuplicate {
            showingDuplicateAlert = true
        } else {
            performSave()
        }
    }

    private func performSave() {
        guard let value = viewModel.value else { return }

        let repository = SnapshotRepository()
        let isEdit = snapshot != nil
        if let snapshot = snapshot {
            let contributionTextIsEmpty = viewModel.contributionString
                .trimmingCharacters(in: .whitespacesAndNewlines)
                .isEmpty
            repository.updateSnapshot(
                snapshot,
                date: viewModel.date,
                value: value,
                contribution: viewModel.contribution,
                notes: viewModel.notes.isEmpty ? nil : viewModel.notes,
                clearContribution: !viewModel.includeContribution || contributionTextIsEmpty,
                clearNotes: viewModel.notes.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
            )
        } else {
            // Capture pre-save goal state for achievement detection
            let goalRepo = GoalRepository()
            let sourceRepo = InvestmentSourceRepository()
            let prevAchievedIds = goalsAchievedBeforeSave(goalRepo: goalRepo, sourceRepo: sourceRepo)

            repository.createSnapshot(
                for: source,
                date: viewModel.date,
                value: value,
                contribution: viewModel.contribution,
                notes: viewModel.notes.isEmpty ? nil : viewModel.notes
            )

            // Check if any goals became achieved
            checkGoalAchievements(goalRepo: goalRepo, sourceRepo: sourceRepo, prevAchievedIds: prevAchievedIds)
        }

        // Reschedule notification
        NotificationService.shared.scheduleReminder(for: source)

        // Log analytics
        FirebaseService.shared.logSnapshotAdded(sourceName: source.name, value: value)

        // When editing, offer to propagate a changed contribution to other snapshots.
        if isEdit, let contribution = viewModel.contribution, viewModel.contributionChanged {
            pendingContribution = contribution
            showingPropagationDialog = true
            return
        }

        dismiss()
    }

    private func propagate(_ direction: SnapshotRepository.ContributionPropagation) {
        if let snapshot = snapshot, let amount = pendingContribution {
            SnapshotRepository().propagateContribution(amount, from: snapshot, direction: direction)
        }
        dismiss()
    }

    private func goalsAchievedBeforeSave(goalRepo: GoalRepository, sourceRepo: InvestmentSourceRepository) -> Set<UUID> {
        let goals = goalRepo.goals.filter { $0.isActive }
        var achieved = Set<UUID>()
        for goal in goals {
            let currentValue: Decimal
            if let accountId = goal.account?.safeId {
                currentValue = sourceRepo.sources
                    .filter { $0.account?.id == accountId }
                    .reduce(Decimal.zero) { $0 + $1.latestValue }
            } else {
                currentValue = sourceRepo.sources.reduce(Decimal.zero) { $0 + $1.latestValue }
            }
            let target = goal.targetDecimal
            if target > 0 && currentValue / target >= 1 {
                achieved.insert(goal.id)
            }
        }
        return achieved
    }

    private func checkGoalAchievements(goalRepo: GoalRepository, sourceRepo: InvestmentSourceRepository, prevAchievedIds: Set<UUID>) {
        // Reload sources to pick up new snapshot value
        let goals = goalRepo.goals.filter { $0.isActive }
        for goal in goals {
            guard !prevAchievedIds.contains(goal.id) else { continue }
            let currentValue: Decimal
            if let accountId = goal.account?.safeId {
                currentValue = sourceRepo.sources
                    .filter { $0.account?.id == accountId }
                    .reduce(Decimal.zero) { $0 + $1.latestValue }
            } else {
                currentValue = sourceRepo.sources.reduce(Decimal.zero) { $0 + $1.latestValue }
            }
            let target = goal.targetDecimal
            if target > 0 && currentValue / target >= 1 {
                NotificationService.shared.scheduleGoalAchievedNotification(goalName: goal.name)
            }
        }
    }
}

#Preview {
    AddSourceView()
        .environmentObject(IAPService())
        .environmentObject(AccountStore(iapService: IAPService()))
}
