import SwiftUI
import CoreData

struct MonthlyCheckInView: View {
    @Environment(\.openURL) private var openURL
    @EnvironmentObject var accountStore: AccountStore
    @StateObject private var viewModel = MonthlyCheckInViewModel()
    @State private var referenceDate: Date

    @State private var monthlyNote: String
    @State private var starRating: Int
    @State private var selectedMood: MonthlyCheckInMood?
    @FocusState private var noteFocused: Bool
    @State private var editingSnapshot: Snapshot?
    @State private var addingSource: InvestmentSource?
    @State private var showBatchUpdate = false
    @State private var showAchievementSatisfactionDialog = false
    @State private var showAppStoreReviewAlert = false

    init(referenceDate: Date = Date()) {
        _referenceDate = State(initialValue: referenceDate)
        _monthlyNote = State(initialValue: MonthlyCheckInStore.note(for: referenceDate))
        _starRating = State(initialValue: MonthlyCheckInStore.rating(for: referenceDate) ?? 0)
        _selectedMood = State(initialValue: MonthlyCheckInStore.mood(for: referenceDate))
    }

    private var lastCompletionDate: Date? {
        MonthlyCheckInStore.latestCompletionDate()
    }

    private var checkInProgress: Double {
        guard let nextDate = nextCheckInDate else { return 1 }
        // Period starts at the first day of the month that opens the interval.
        // e.g. monthly → Feb 1; quarterly → Jan 1 (3 months ending Mar 31)
        let periodStart = nextDate.adding(months: -(checkInIntervalMonths - 1)).startOfMonth
        let totalDays = Double(max(1, periodStart.startOfDay.daysBetween(nextDate.startOfDay)))
        let elapsedDays = Double(max(0, periodStart.startOfDay.daysBetween(Date().startOfDay)))
        return min(elapsedDays / totalDays, 1)
    }

    private var checkInIntervalMonths: Int {
        if accountStore.showAllAccounts || accountStore.selectedAccount == nil {
            return NotificationFrequency.monthly.months
        }
        let account = accountStore.selectedAccount
        let frequency = account?.frequency ?? .monthly
        if frequency == .custom {
            return max(1, Int(account?.customFrequencyMonths ?? 1))
        }
        if frequency == .never {
            return NotificationFrequency.monthly.months
        }
        return frequency.months
    }

    private var nextCheckInDate: Date? {
        guard let last = lastCompletionDate else { return nil }
        let effective = MonthlyCheckInStore.effectiveMonth(for: last, relativeTo: last)
        return effective.adding(months: checkInIntervalMonths).endOfMonth
    }

    private var isOverdue: Bool {
        guard let next = nextCheckInDate else { return false }
        return Date() > next
    }

    private var daysUntilDeadline: Int? {
        guard let next = nextCheckInDate else { return nil }
        return Calendar.current.dateComponents([.day], from: Date().startOfDay, to: next.startOfDay).day
    }

    private var progressBarTint: Color {
        if isOverdue { return .red }
        if let days = daysUntilDeadline, days <= 3 { return .orange }
        return .appSecondary
    }

    private var canGoToNextMonth: Bool {
        guard let nextMonth = Calendar.current.date(byAdding: .month, value: 1, to: referenceDate) else { return false }
        return nextMonth <= Date()
    }

    private func navigateMonth(offset: Int) {
        guard let newDate = Calendar.current.date(byAdding: .month, value: offset, to: referenceDate) else { return }
        referenceDate = newDate
        monthlyNote = MonthlyCheckInStore.note(for: newDate)
        starRating = MonthlyCheckInStore.rating(for: newDate) ?? 0
        selectedMood = MonthlyCheckInStore.mood(for: newDate)
        viewModel.selectedRange = DateRange.month(containing: newDate)
        viewModel.refresh()
    }

    private var canAddNewCheckIn: Bool {
        true
    }

    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                headerCard
                summaryCard
                monthlyHighlightsCard
                reflectionCard
                sourcesCard
                notesCard
                journalCard
            }
            .padding()
        }
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .principal) {
                HStack(spacing: 12) {
                    Button {
                        navigateMonth(offset: -1)
                    } label: {
                        Image(systemName: "chevron.left")
                            .font(.subheadline.weight(.semibold))
                            .foregroundColor(.appPrimary)
                    }

                    Text(monthLabel)
                        .font(.headline)

                    Button {
                        navigateMonth(offset: 1)
                    } label: {
                        Image(systemName: "chevron.right")
                            .font(.subheadline.weight(.semibold))
                            .foregroundColor(canGoToNextMonth ? .appPrimary : .secondary.opacity(0.3))
                    }
                    .disabled(!canGoToNextMonth)
                }
            }

            ToolbarItem(placement: .navigationBarTrailing) {
                Button {
                    shareMonthlyCheckIn()
                } label: {
                    Image(systemName: "square.and.arrow.up")
                }
            }
        }
        .onAppear {
            viewModel.selectedAccount = accountStore.selectedAccount
            viewModel.showAllAccounts = accountStore.showAllAccounts
            viewModel.selectedRange = DateRange.month(containing: referenceDate)
            viewModel.refresh()
            monthlyNote = MonthlyCheckInStore.note(for: referenceDate)
            starRating = MonthlyCheckInStore.rating(for: referenceDate) ?? 0
            selectedMood = MonthlyCheckInStore.mood(for: referenceDate)
        }
        .onReceive(NotificationCenter.default.publisher(for: .NSManagedObjectContextObjectsDidChange)) { _ in
            monthlyNote = MonthlyCheckInStore.note(for: referenceDate)
            starRating = MonthlyCheckInStore.rating(for: referenceDate) ?? 0
            selectedMood = MonthlyCheckInStore.mood(for: referenceDate)
        }
        .onReceive(accountStore.$selectedAccount) { account in
            viewModel.selectedAccount = account
            viewModel.selectedRange = DateRange.month(containing: referenceDate)
            viewModel.refresh()
        }
        .onReceive(accountStore.$showAllAccounts) { showAll in
            viewModel.showAllAccounts = showAll
            viewModel.selectedRange = DateRange.month(containing: referenceDate)
            viewModel.refresh()
        }
        .sheet(item: $editingSnapshot) { snapshot in
            if let source = snapshot.source {
                AddSnapshotView(source: source, snapshot: snapshot)
            }
        }
        .sheet(item: $addingSource) { source in
            AddSnapshotView(source: source)
        }
        .sheet(isPresented: $showBatchUpdate) {
            viewModel.refresh()
        } content: {
            let batchSaveDate = referenceDate.isSameMonth(as: Date()) ? Date() : referenceDate.endOfMonth
            BatchUpdateView(sources: viewModel.sources, saveDate: batchSaveDate)
        }
        .onChange(of: starRating) { _, newValue in
            MonthlyCheckInStore.setRating(newValue == 0 ? nil : newValue, for: referenceDate)
        }
        .onChange(of: selectedMood) { _, newValue in
            MonthlyCheckInStore.setMood(newValue, for: referenceDate)
        }
        .confirmationDialog(
            "checkin_enjoying_dialog_title",
            isPresented: $showAchievementSatisfactionDialog,
            titleVisibility: .visible
        ) {
            ForEach(1...5, id: \.self) { value in
                Button(value == 1
                    ? String(localized: "rating_1_star")
                    : String(format: NSLocalizedString("rating_n_stars", comment: ""), value)
                ) {
                    if value == 5 {
                        showAppStoreReviewAlert = true
                    }
                }
            }
            Button(String(localized: "not_now"), role: .cancel) {}
        } message: {
            Text("checkin_enjoying_dialog_message")
        }
        .alert("app_store_review_title", isPresented: $showAppStoreReviewAlert) {
            Button(String(localized: "not_now"), role: .cancel) {}
            Button(String(localized: "write_review")) {
                ReviewPromptService.shared.markStoreReviewCompleted()
                openURL(ReviewPromptService.appStoreWriteReviewURL())
            }
        } message: {
            Text("app_store_review_message")
        }
    }

    private var headerCard: some View {
        VStack(alignment: .leading, spacing: 8) {
            if referenceDate.isSameMonth(as: Date()) {
                VStack(alignment: .leading, spacing: 6) {
                    ProgressView(value: checkInProgress)
                        .tint(progressBarTint)

                    if let nextDate = nextCheckInDate {
                        Text(
                            String(
                                format: NSLocalizedString("next_check_in", comment: ""),
                                nextDate.mediumDateString
                            )
                        )
                            .font(.caption)
                            .foregroundColor(.secondary)
                    } else {
                        Text("Start your first check-in anytime.")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                }
            }

            if let completed = MonthlyCheckInStore.completionDate(for: referenceDate) {
                HStack(spacing: 6) {
                    Image(systemName: "checkmark.circle.fill")
                        .foregroundColor(.positiveGreen)
                    Text("Completed \(completed.friendlyDescription)")
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            }

            Button {
                let previousUnlockedAchievementKeys = unlockedAchievementKeys()
                let now = Date()
                let completionDate = referenceDate.isSameMonth(as: now)
                    ? now
                    : min(referenceDate.endOfMonth, now)
                MonthlyCheckInStore.setCompletionDate(completionDate, for: referenceDate)
                ReviewPromptService.shared.recordMonthlyCheckInCompleted()
                NotificationService.shared.scheduleMonthlyCheckIn()
                viewModel.refresh()
                let newlyUnlockedAchievementKeys = unlockedAchievementKeys().subtracting(previousUnlockedAchievementKeys)
                if ReviewPromptService.shared.shouldAskForAchievementSatisfaction(
                    newlyUnlockedAchievementKeys: newlyUnlockedAchievementKeys
                ) {
                    showAchievementSatisfactionDialog = true
                }
            } label: {
                let isCompleted = MonthlyCheckInStore.completionDate(for: referenceDate) != nil
                Text(isCompleted ? "Update Check-in" : "Mark Check-in Complete")
                    .font(.subheadline.weight(.semibold))
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 10)
                    .background(isCompleted ? Color.appSecondary.opacity(0.1) : Color.appPrimary.opacity(0.1))
                    .cornerRadius(AppConstants.UI.cornerRadius)
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var monthLabel: String {
        Self.monthLabel(for: referenceDate, relativeTo: Date(), locale: .current)
    }

    private func unlockedAchievementKeys() -> Set<String> {
        Set(
            MonthlyCheckInStore
                .achievementStatuses(referenceDate: referenceDate)
                .filter(\.isUnlocked)
                .map(\.id)
        )
    }

    static func monthLabel(for date: Date, relativeTo referenceDate: Date, locale: Locale) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = "LLLL yyyy"
        formatter.locale = locale
        let effectiveMonth = MonthlyCheckInStore.effectiveMonth(for: date, relativeTo: referenceDate)
        return formatter.string(from: effectiveMonth)
    }

    private var reflectionCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Monthly Pulse")
                    .font(.headline)
                Spacer()
                Text("Optional")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            VStack(alignment: .leading, spacing: 8) {
                Text("Rate this month")
                    .font(.subheadline.weight(.semibold))

                HStack(spacing: 8) {
                    ForEach(1...5, id: \.self) { value in
                        Button {
                            withAnimation(.easeInOut(duration: AppConstants.Animation.shortDuration)) {
                                starRating = value == starRating ? 0 : value
                            }
                        } label: {
                            Image(systemName: value <= starRating ? "star.fill" : "star")
                                .font(.title3)
                                .foregroundColor(value <= starRating ? .appSecondary : .secondary)
                                .padding(8)
                                .background(
                                    Circle()
                                        .fill(value <= starRating ? Color.appSecondary.opacity(0.12) : Color.gray.opacity(0.08))
                                )
                        }
                        .buttonStyle(.plain)
                    }

                    Button {
                        withAnimation(.easeInOut(duration: AppConstants.Animation.shortDuration)) {
                            starRating = 0
                        }
                    } label: {
                        Text("Skip")
                            .font(.caption.weight(.semibold))
                            .padding(.horizontal, 10)
                            .padding(.vertical, 6)
                            .background(Color.gray.opacity(0.12))
                            .cornerRadius(AppConstants.UI.smallCornerRadius)
                    }
                }
            }

            VStack(alignment: .leading, spacing: 8) {
                Text("How did it feel?")
                    .font(.subheadline.weight(.semibold))

                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 10) {
                        ForEach(MonthlyCheckInMood.allCases) { mood in
                            Button {
                                withAnimation(.easeInOut(duration: AppConstants.Animation.shortDuration)) {
                                    selectedMood = selectedMood == mood ? nil : mood
                                }
                            } label: {
                                moodPill(for: mood)
                            }
                            .buttonStyle(.plain)
                        }
                    }
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var summaryCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Monthly Summary")
                .font(.headline)

            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Starting")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    Text(viewModel.monthlySummary.formattedStartingValue)
                        .font(.subheadline.weight(.semibold))
                }
                Spacer()
                VStack(alignment: .trailing, spacing: 4) {
                    Text("Ending")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    Text(viewModel.monthlySummary.formattedEndingValue)
                        .font(.subheadline.weight(.semibold))
                }
            }

            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Contributions")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    Text(viewModel.monthlySummary.formattedContributions)
                        .font(.subheadline.weight(.semibold))
                }
                Spacer()
                VStack(alignment: .trailing, spacing: 4) {
                    Text("Net Performance")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    Text("\(viewModel.monthlySummary.formattedNetPerformance) (\(viewModel.monthlySummary.formattedNetPerformancePercentage))")
                        .font(.subheadline.weight(.semibold))
                        .foregroundColor(viewModel.monthlySummary.netPerformance >= 0 ? .positiveGreen : .negativeRed)
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var sourcePerformances: [(name: String, diff: Decimal, percentage: Double)] {
        viewModel.sources.compactMap { source -> (name: String, diff: Decimal, percentage: Double)? in
            let snapshots = source.sortedSnapshotsByDateAscending
            guard snapshots.count >= 2 else { return nil }
            let latest = snapshots[snapshots.count - 1]
            let previous = snapshots[snapshots.count - 2]
            let diff = latest.decimalValue - previous.decimalValue
            let pct = previous.decimalValue > 0
                ? NSDecimalNumber(decimal: diff / previous.decimalValue * 100).doubleValue
                : 0
            return (name: source.name, diff: diff, percentage: pct)
        }
    }

    @ViewBuilder
    private var monthlyHighlightsCard: some View {
        let perfs = sourcePerformances
        if perfs.count >= 2 {
            let best = perfs.max(by: { $0.percentage < $1.percentage })
            let worst = perfs.min(by: { $0.percentage < $1.percentage })
            let bestContributor = perfs.max(by: { abs($0.diff) < abs($1.diff) })
            VStack(alignment: .leading, spacing: 12) {
                Text("Monthly Highlights")
                    .font(.headline)

                if let best {
                    highlightRow(
                        icon: "arrow.up.circle.fill",
                        iconColor: .positiveGreen,
                        label: "Best Performer",
                        name: best.name,
                        percentage: best.percentage,
                        diff: best.diff,
                        valueColor: .positiveGreen
                    )
                }

                if let worst, worst.name != best?.name {
                    highlightRow(
                        icon: "arrow.down.circle.fill",
                        iconColor: .negativeRed,
                        label: "Worst Performer",
                        name: worst.name,
                        percentage: worst.percentage,
                        diff: worst.diff,
                        valueColor: .negativeRed
                    )
                }

                if let contributor = bestContributor,
                   contributor.name != best?.name {
                    highlightRow(
                        icon: "star.circle.fill",
                        iconColor: .appAccent,
                        label: "Best Contributor",
                        name: contributor.name,
                        percentage: contributor.percentage,
                        diff: contributor.diff,
                        valueColor: .financialColor(for: contributor.diff)
                    )
                }
            }
            .padding()
            .background(Color(.systemBackground))
            .cornerRadius(AppConstants.UI.cornerRadius)
            .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
        }
    }

    private func highlightRow(icon: String, iconColor: Color, label: String, name: String, percentage: Double, diff: Decimal, valueColor: Color) -> some View {
        HStack {
            Image(systemName: icon)
                .foregroundColor(iconColor)
            VStack(alignment: .leading, spacing: 2) {
                Text(label)
                    .font(.caption)
                    .foregroundColor(.secondary)
                Text(name)
                    .font(.subheadline.weight(.semibold))
            }
            Spacer()
            VStack(alignment: .trailing, spacing: 2) {
                Text(String(format: "%+.1f%%", percentage))
                    .font(.subheadline.weight(.bold))
                    .foregroundColor(valueColor)
                Text("(\(diff.compactCurrencyString))")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
    }

    private var sourcesCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Update Sources")
                    .font(.headline)
                Spacer()
                if viewModel.sources.count > 1 {
                    Button {
                        showBatchUpdate = true
                    } label: {
                        Label("Batch Update", systemImage: "square.and.pencil")
                            .font(.caption.weight(.semibold))
                            .foregroundColor(.appPrimary)
                    }
                }
                Text("\(viewModel.sources.count)")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }

            if viewModel.sources.isEmpty {
                Text("Add sources to start your monthly check-in.")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            } else {
                ForEach(viewModel.sources, id: \.objectID) { source in
                    let latestSnapshot = source.latestSnapshot
                    let updatedThisCycle = isSnapshotInCurrentCycle(latestSnapshot)
                    let snapshots = source.sortedSnapshotsByDateAscending
                    let previousSnapshot: Snapshot? = {
                        guard snapshots.count >= 2 else { return nil }
                        return snapshots[snapshots.count - 2]
                    }()
                    let valueDiff: Decimal? = {
                        guard let latest = latestSnapshot, let previous = previousSnapshot else { return nil }
                        return latest.decimalValue - previous.decimalValue
                    }()
                    Button {
                        if updatedThisCycle, let snapshot = latestSnapshot {
                            editingSnapshot = snapshot
                        } else {
                            addingSource = source
                        }
                    } label: {
                        HStack {
                            Circle()
                                .fill(source.category?.color ?? .gray)
                                .frame(width: 8, height: 8)

                            VStack(alignment: .leading, spacing: 2) {
                                Text(source.name)
                                    .font(.subheadline.weight(.medium))
                                Text(updatedThisCycle ? "Updated this cycle" : "Needs update")
                                    .font(.caption2)
                                    .foregroundColor(updatedThisCycle ? .positiveGreen : .secondary)
                            }

                            Spacer()

                            if let diff = valueDiff, updatedThisCycle {
                                Text(diff >= 0 ? "+\(diff.compactCurrencyString)" : diff.compactCurrencyString)
                                    .font(.caption.weight(.semibold))
                                    .foregroundColor(diff >= 0 ? .positiveGreen : .negativeRed)
                            }

                            Text(latestSnapshot?.date.relativeDayDescription ?? String(localized: "date_never"))
                                .font(.caption)
                                .foregroundColor(.secondary)

                            Image(systemName: "chevron.right")
                                .font(.caption)
                                .foregroundColor(.secondary)
                        }
                    }
                    .buttonStyle(.plain)
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var notesCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Monthly Note")
                .font(.headline)

            TextEditor(text: $monthlyNote)
                .frame(minHeight: 120)
                .padding(8)
                .background(Color.gray.opacity(0.08))
                .cornerRadius(12)
                .focused($noteFocused)
                .onChange(of: monthlyNote) { _, newValue in
                    MonthlyCheckInStore.setNote(newValue, for: referenceDate)
                }

            HStack(spacing: 12) {
                NavigationLink {
                    MonthlyNoteEditorView(date: referenceDate, note: $monthlyNote)
                } label: {
                    Text("Open Full Note")
                        .font(.subheadline.weight(.semibold))
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 8)
                        .background(Color.appSecondary.opacity(0.12))
                        .cornerRadius(AppConstants.UI.cornerRadius)
                }
                .buttonStyle(.plain)

                Button {
                    viewModel.duplicatePreviousMonthSnapshots(referenceDate: referenceDate)
                    viewModel.refresh()
                } label: {
                    Text("Duplicate Previous")
                        .font(.subheadline.weight(.semibold))
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 8)
                        .background(Color.appPrimary.opacity(0.12))
                        .cornerRadius(AppConstants.UI.cornerRadius)
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private var journalCard: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Snapshot Notes")
                .font(.headline)

            if viewModel.recentNotes.isEmpty {
                Text("No snapshot notes for this month.")
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            } else {
                ForEach(viewModel.recentNotes, id: \.objectID) { snapshot in
                    VStack(alignment: .leading, spacing: 4) {
                        Text(snapshot.source?.name ?? "Source")
                            .font(.subheadline.weight(.semibold))
                        Text(snapshot.notes ?? "")
                            .font(.subheadline)
                            .foregroundColor(.secondary)
                        Text(snapshot.date.friendlyDescription)
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }

                    if snapshot.id != viewModel.recentNotes.last?.id {
                        Divider()
                    }
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private func shareMonthlyCheckIn() {
        let summary = viewModel.monthlySummary
        ShareService.shared.shareMonthlyCheckIn(summary: summary, appName: appDisplayName)
    }

    private var appDisplayName: String {
        if let name = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
            return name
        }
        if let name = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
            return name
        }
        return "Portfolio Journal"
    }
}

struct AchievementsView: View {
    let referenceDate: Date

    private var achievementStatuses: [MonthlyCheckInAchievementStatus] {
        MonthlyCheckInStore.achievementStatuses(referenceDate: referenceDate)
    }

    private var unlockedAchievements: [MonthlyCheckInAchievementStatus] {
        achievementStatuses.filter { $0.isUnlocked }
    }

    private var lockedAchievements: [MonthlyCheckInAchievementStatus] {
        achievementStatuses.filter { !$0.isUnlocked }
    }

    var body: some View {
        ScrollView {
            VStack(spacing: 16) {
                headerCard

                achievementSection(
                    title: String(localized: "achievements_unlocked_title"),
                    subtitle: unlockedAchievements.isEmpty
                        ? String(localized: "achievements_unlocked_empty")
                        : nil,
                    achievements: unlockedAchievements,
                    isLocked: false
                )

                achievementSection(
                    title: String(localized: "achievements_locked_title"),
                    subtitle: lockedAchievements.isEmpty
                        ? String(localized: "achievements_locked_empty")
                        : nil,
                    achievements: lockedAchievements,
                    isLocked: true
                )
            }
            .padding()
        }
        .navigationTitle(String(localized: "achievements_nav_title"))
        .navigationBarTitleDisplayMode(.inline)
    }

    private var headerCard: some View {
        let total = max(achievementStatuses.count, 1)
        let unlockedCount = unlockedAchievements.count

        return VStack(alignment: .leading, spacing: 8) {
            Text(String(localized: "achievements_progress_title"))
                .font(.headline)

            AchievementMilestoneBar(statuses: achievementStatuses)

            Text(
                String(
                    format: NSLocalizedString("achievements_unlocked_count", comment: ""),
                    unlockedCount,
                    total
                )
            )
                .font(.subheadline)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private func achievementSection(
        title: String,
        subtitle: String?,
        achievements: [MonthlyCheckInAchievementStatus],
        isLocked: Bool
    ) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Text(title)
                .font(.headline)

            if let subtitle {
                Text(subtitle)
                    .font(.subheadline)
                    .foregroundColor(.secondary)
            }

            if achievements.isEmpty {
                EmptyView()
            } else {
                ForEach(achievements) { status in
                    achievementRow(status, isLocked: isLocked)
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(AppConstants.UI.cornerRadius)
        .shadow(color: .black.opacity(0.05), radius: 8, y: 2)
    }

    private func achievementRow(_ status: MonthlyCheckInAchievementStatus, isLocked: Bool) -> some View {
        HStack(alignment: .center, spacing: 12) {
            ZStack {
                Circle()
                    .fill(isLocked ? Color.gray.opacity(0.2) : Color.appSecondary.opacity(0.18))
                    .frame(width: 42, height: 42)
                Image(systemName: status.achievement.icon)
                    .font(.headline)
                    .foregroundColor(isLocked ? .secondary : .appSecondary)
            }

            VStack(alignment: .leading, spacing: 2) {
                Text(status.achievement.title)
                    .font(.subheadline.weight(.semibold))
                Text(status.achievement.detail)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            Spacer()

            if isLocked {
                Image(systemName: "lock.fill")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
        .padding(10)
        .background(isLocked ? Color.gray.opacity(0.08) : Color.appSecondary.opacity(0.12))
        .cornerRadius(AppConstants.UI.smallCornerRadius)
    }
}

private extension MonthlyCheckInView {
    func isSnapshotInCurrentCycle(_ snapshot: Snapshot?) -> Bool {
        guard let snapshot, let last = lastCompletionDate else { return false }
        return snapshot.date >= Calendar.current.startOfDay(for: last)
    }

    @ViewBuilder
    func moodPill(for mood: MonthlyCheckInMood) -> some View {
        let isSelected = selectedMood == mood
        HStack(alignment: .center, spacing: 8) {
            Image(systemName: mood.iconName)
                .font(.body)
                .foregroundColor(isSelected ? moodColor(for: mood) : .secondary)
            VStack(alignment: .leading, spacing: 2) {
                Text(mood.title)
                    .font(.subheadline.weight(.semibold))
                Text(mood.detail)
                    .font(.caption2)
                    .foregroundColor(.secondary)
            }
        }
        .padding(10)
        .background(isSelected ? moodColor(for: mood).opacity(0.16) : Color.gray.opacity(0.08))
        .overlay(
            RoundedRectangle(cornerRadius: AppConstants.UI.smallCornerRadius)
                .stroke(isSelected ? moodColor(for: mood) : Color.clear, lineWidth: 1)
        )
        .cornerRadius(AppConstants.UI.smallCornerRadius)
    }

    func moodColor(for mood: MonthlyCheckInMood) -> Color {
        switch mood {
        case .energized: return .appSecondary
        case .confident: return .appPrimary
        case .balanced: return .teal
        case .cautious: return .orange
        case .stressed: return .red
        }
    }

}

// MARK: - Achievement Milestone Bar

struct AchievementMilestoneBar: View {
    let statuses: [MonthlyCheckInAchievementStatus]

    var body: some View {
        let sorted = statuses.sorted { $0.isUnlocked && !$1.isUnlocked }
        let unlockedCount = sorted.filter(\.isUnlocked).count
        let total = max(sorted.count, 1)
        let progress = Double(unlockedCount) / Double(total)

        GeometryReader { geo in
            let barWidth = geo.size.width
            let circleSize: CGFloat = 18
            let barY = geo.size.height / 2

            // Background track
            Capsule()
                .fill(Color.gray.opacity(0.2))
                .frame(width: barWidth, height: 6)
                .position(x: barWidth / 2, y: barY)

            // Filled track
            Capsule()
                .fill(Color.positiveGreen)
                .frame(width: barWidth * progress, height: 6)
                .position(x: barWidth * progress / 2, y: barY)

            // Milestone circles on the bar
            ForEach(Array(sorted.enumerated()), id: \.element.id) { index, status in
                let x = total == 1
                    ? barWidth / 2
                    : circleSize / 2 + (barWidth - circleSize) * Double(index) / Double(total - 1)

                ZStack {
                    Circle()
                        .fill(status.isUnlocked ? Color.positiveGreen : Color.gray.opacity(0.3))
                        .frame(width: circleSize, height: circleSize)
                    Circle()
                        .stroke(Color(.systemBackground), lineWidth: 2)
                        .frame(width: circleSize, height: circleSize)

                    if status.isUnlocked {
                        Image(systemName: "checkmark")
                            .font(.system(size: 8, weight: .bold))
                            .foregroundColor(.white)
                    }
                }
                .position(x: x, y: barY)
            }
        }
        .frame(height: 24)
    }
}

// MARK: - Batch Update View

struct BatchUpdateView: View {
    @Environment(\.dismiss) private var dismiss
    let sources: [InvestmentSource]
    let saveDate: Date
    @State private var values: [UUID: String] = [:]
    @State private var contributions: [UUID: String] = [:]
    @State private var savedCount = 0

    init(sources: [InvestmentSource], saveDate: Date = Date()) {
        self.sources = sources
        self.saveDate = saveDate
    }

    var body: some View {
        NavigationStack {
            List {
                ForEach(sources, id: \.objectID) { source in
                    sourceRow(source)
                }

                if filledCount > 0 {
                    Section {
                        Button {
                            saveAll()
                        } label: {
                            Text(filledCount == 1
                            ? String(localized: "save_1_snapshot")
                            : String(format: NSLocalizedString("save_n_snapshots", comment: ""), filledCount))
                                .font(.headline)
                                .frame(maxWidth: .infinity)
                        }
                    }
                }
            }
            .navigationTitle("Batch Update")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") { dismiss() }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") { saveAll() }
                        .disabled(filledCount == 0)
                        .fontWeight(.semibold)
                }
            }
            .onAppear {
                prefillCurrentValues()
            }
        }
    }

    private func sourceRow(_ source: InvestmentSource) -> some View {
        let currencyCode = source.account?.currency
            ?? AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
        let symbol = CurrencyFormatter.symbol(for: currencyCode)
        let previousValue = source.latestSnapshot?.decimalValue
        let isDetailed = InputMode(rawValue: source.account?.inputMode ?? "") == .detailed
        let valueBinding = Binding<String>(
            get: { values[source.id] ?? "" },
            set: { values[source.id] = $0 }
        )
        let contributionBinding = Binding<String>(
            get: { contributions[source.id] ?? "" },
            set: { contributions[source.id] = $0 }
        )

        return VStack(alignment: .leading, spacing: 6) {
            HStack(spacing: 8) {
                Circle()
                    .fill(source.category?.color ?? .gray)
                    .frame(width: 8, height: 8)
                Text(source.name)
                    .font(.subheadline.weight(.medium))
                Spacer()
                if let prev = previousValue {
                    Text(prev.currencyString)
                        .font(.caption)
                        .foregroundColor(.secondary)
                }
            }

            HStack {
                Text(symbol)
                    .foregroundColor(.secondary)
                TextField("Current value", text: valueBinding)
                    .keyboardType(.decimalPad)
            }
            .padding(8)
            .background(Color.gray.opacity(0.08))
            .cornerRadius(8)

            if isDetailed {
                HStack {
                    Image(systemName: "plus.circle")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    TextField("Contribution this period (optional)", text: contributionBinding)
                        .keyboardType(.decimalPad)
                        .font(.subheadline)
                        .foregroundColor(.secondary)
                }
                .padding(8)
                .background(Color.appSecondary.opacity(0.06))
                .cornerRadius(8)
            }
        }
        .padding(.vertical, 2)
    }

    private var filledCount: Int {
        values.values.filter { !$0.trimmingCharacters(in: .whitespaces).isEmpty }.count
    }

    private func prefillCurrentValues() {
        for source in sources {
            guard values[source.id] == nil,
                  let latest = source.latestSnapshot else { continue }
            let currencyCode = source.account?.currency
                ?? AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
            values[source.id] = CurrencyFormatter.formatForInput(latest.decimalValue, currencyCode: currencyCode)
        }
    }

    private func saveAll() {
        let repository = SnapshotRepository()
        var count = 0

        for source in sources {
            guard let input = values[source.id],
                  !input.trimmingCharacters(in: .whitespaces).isEmpty else { continue }

            let currencyCode = source.account?.currency
                ?? AppSettings.getOrCreate(in: CoreDataStack.shared.viewContext).currency
            let symbol = CurrencyFormatter.symbol(for: currencyCode)

            guard let parsed = CurrencyFormatter.parseUserInput(input, currencySymbol: symbol),
                  parsed >= 0 else { continue }

            let contributionInput = contributions[source.id] ?? ""
            let parsedContribution: Decimal? = contributionInput.trimmingCharacters(in: .whitespaces).isEmpty
                ? nil
                : CurrencyFormatter.parseUserInput(contributionInput, currencySymbol: symbol)

            repository.createSnapshot(
                for: source,
                date: saveDate,
                value: parsed,
                contribution: parsedContribution
            )
            NotificationService.shared.scheduleReminder(for: source)
            count += 1
        }

        savedCount = count
        dismiss()
    }
}

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