import SwiftUI
import Models
import MailStore
import SyncEngine
import TaskStore

struct ContentView: View {
	@State private var viewModel = MailViewModel()
	@State private var accountSetup = AccountSetupViewModel()
	@State private var showingAccountSetup = false
	@State private var composeMode: ComposeMode?
	@State private var showTaskEditor = false

	var body: some View {
		Group {
			if viewModel.hasAccount {
				mailView
			} else {
				NavigationStack {
					AccountSetupView(viewModel: accountSetup) {
						connectAccount()
					}
				}
			}
		}
		.onAppear {
			loadExistingAccount()
		}
	}

	private var mailView: some View {
		NavigationSplitView {
			SidebarView(viewModel: viewModel)
				.toolbar {
					ToolbarItem(placement: .automatic) {
						Button {
							composeMode = .new
						} label: {
							Label("New Message", systemImage: "square.and.pencil")
						}
						.keyboardShortcut("n", modifiers: .command)
						.help("New Message (⌘N)")
					}
					ToolbarItem(placement: .automatic) {
						Button {
							showTaskEditor = true
						} label: {
							Label("New Task", systemImage: "plus.circle")
						}
						.keyboardShortcut("t", modifiers: .command)
						.help("New Task (⌘T)")
					}
				}
		} content: {
			ThreadListView(viewModel: viewModel)
		} detail: {
			ThreadDetailView(
				thread: viewModel.selectedThread,
				messages: viewModel.messages,
				linkedTasks: viewModel.selectedThread.map { viewModel.tasksLinkedToThread(threadId: $0.id) } ?? [],
				onComposeRequest: { mode in
					requestCompose(mode)
				}
			)
		}
		.safeAreaInset(edge: .bottom) {
			statusBanner
		}
		.sheet(item: composeModeBinding) { wrapper in
			if let config = viewModel.accountConfig,
			   let store = viewModel.store,
			   let actionQueue = viewModel.actionQueue {
				ComposeView(
					viewModel: ComposeViewModel(
						mode: wrapper.mode,
						accountConfig: config,
						store: store,
						actionQueue: actionQueue
					)
				)
			}
		}
		.sheet(isPresented: $showTaskEditor) {
			if let config = viewModel.accountConfig,
			   let taskStore = viewModel.taskStore {
				TaskEditView(
					viewModel: TaskEditViewModel(
						accountId: config.id,
						taskStore: taskStore
					)
				)
			}
		}
		.task {
			await viewModel.syncNow()
			viewModel.startPeriodicSync()
		}
	}

	private var composeModeBinding: Binding<ComposeModeWrapper?> {
		Binding(
			get: {
				composeMode.map { ComposeModeWrapper(mode: $0) }
			},
			set: { wrapper in
				composeMode = wrapper?.mode
			}
		)
	}

	@ViewBuilder
	private var statusBanner: some View {
		switch viewModel.syncState {
		case .error(let message):
			HStack {
				Image(systemName: "wifi.slash")
				Text("Offline — showing cached mail")
				Spacer()
				Button("Retry") {
					Task { await viewModel.syncNow() }
				}
				.buttonStyle(.borderless)
			}
			.font(.caption)
			.padding(8)
			.background(.yellow.opacity(0.2))
		case .syncing(let mailbox):
			HStack {
				ProgressView()
					.controlSize(.small)
				Text("Syncing\(mailbox.map { " \($0)" } ?? "")…")
					.font(.caption)
				Spacer()
			}
			.padding(8)
			.background(.blue.opacity(0.1))
		case .idle:
			EmptyView()
		}
	}

	/// Fetch message body if needed, then present compose sheet.
	private func requestCompose(_ mode: ComposeMode) {
		Task {
			switch mode {
			case .reply(let msg):
				let loaded = await viewModel.ensureBodyLoaded(for: msg)
				composeMode = .reply(to: loaded)
			case .replyAll(let msg):
				let loaded = await viewModel.ensureBodyLoaded(for: msg)
				composeMode = .replyAll(to: loaded)
			case .forward(let msg):
				let loaded = await viewModel.ensureBodyLoaded(for: msg)
				composeMode = .forward(of: loaded)
			case .new, .draft:
				composeMode = mode
			}
		}
	}

	private func connectAccount() {
		guard let (config, credentials) = accountSetup.buildConfig() else { return }
		do {
			try viewModel.setup(config: config, credentials: credentials)
			try KeychainService.saveCredentials(credentials, for: config.id)
			if let data = try? JSONEncoder().encode(config) {
				UserDefaults.standard.set(data, forKey: "accountConfig")
			}
			Task {
				await viewModel.syncNow()
				await viewModel.loadMailboxes(accountId: config.id)
				viewModel.startObservingThreads(accountId: config.id)
				viewModel.startPeriodicSync()
			}
		} catch {
			accountSetup.errorMessage = error.localizedDescription
		}
	}

	private func loadExistingAccount() {
		guard let data = UserDefaults.standard.data(forKey: "accountConfig"),
			  let config = try? JSONDecoder().decode(AccountConfig.self, from: data),
			  let credentials = try? KeychainService.loadCredentials(for: config.id)
		else { return }
		do {
			try viewModel.setup(config: config, credentials: credentials)
			Task {
				await viewModel.loadMailboxes(accountId: config.id)
				viewModel.startObservingThreads(accountId: config.id)
				await viewModel.syncNow()
				viewModel.startPeriodicSync()
			}
		} catch {
			// Account config exists but setup failed — show account setup
		}
	}
}

// Wrapper to make ComposeMode Identifiable for .sheet(item:)
struct ComposeModeWrapper: Identifiable {
	let id = UUID()
	let mode: ComposeMode
}
