import SwiftUI
import Models
import MailStore

struct ThreadListView: View {
	@Bindable var viewModel: MailViewModel
	@State var showMoveSheet = false
	@State var showDeferPicker = false
	@State var showLabelPicker = false

	/// Whether the current view shows a GTD perspective (vs. a raw mailbox folder)
	private var isGTDPerspective: Bool {
		// GTD perspectives are active when items are loaded
		!viewModel.items.isEmpty || viewModel.selectedMailbox == nil
	}

	var body: some View {
		Group {
			if !viewModel.items.isEmpty {
				itemListView
			} else {
				threadListView
			}
		}
		.sheet(isPresented: $showMoveSheet) {
			MoveToSheet(mailboxes: viewModel.mailboxes) { mailbox in
				viewModel.moveSelectedThread(to: mailbox)
			}
		}
		.popover(isPresented: $showDeferPicker) {
			DeferPicker { date in
				if let selectedItem = selectedItemSummary {
					viewModel.deferItem(selectedItem, until: date)
				}
			}
		}
		.sheet(isPresented: $showLabelPicker) {
			LabelPicker(
				labels: availableLabels,
				onSelect: { label in
					if let selectedItem = selectedItemSummary {
						viewModel.fileItem(selectedItem, label: label)
					}
				},
				onCreate: { name in
					createAndFileLabel(name: name)
				}
			)
		}
	}

	// MARK: - Unified Item List (GTD perspectives)

	private var itemListView: some View {
		List(viewModel.items) { item in
			ItemRow(item: item)
				.tag(item.id)
		}
		.listStyle(.inset)
		.navigationTitle(viewModel.selectedPerspective.label)
		.overlay {
			if viewModel.items.isEmpty {
				ContentUnavailableView(
					"No Items",
					systemImage: viewModel.selectedPerspective.systemImage,
					description: Text("Nothing in \(viewModel.selectedPerspective.label)")
				)
			}
		}
		.toolbar {
			gtdToolbarItems
		}
	}

	// MARK: - Thread List (folder view)

	private var threadListView: some View {
		List(viewModel.threads, selection: Binding(
			get: { viewModel.selectedThread?.id },
			set: { newId in
				if let thread = viewModel.threads.first(where: { $0.id == newId }) {
					viewModel.selectThread(thread)
				}
			}
		)) { thread in
			ThreadRow(thread: thread)
				.tag(thread.id)
				.swipeActions(edge: .leading) {
					Button {
						viewModel.selectThread(thread)
						viewModel.archiveSelectedThread()
					} label: {
						Label("Archive", systemImage: "archivebox")
					}
					.tint(.green)
				}
				.swipeActions(edge: .trailing) {
					Button(role: .destructive) {
						viewModel.selectThread(thread)
						viewModel.deleteSelectedThread()
					} label: {
						Label("Delete", systemImage: "trash")
					}
				}
		}
		.listStyle(.inset)
		.navigationTitle(viewModel.selectedMailbox?.name ?? "Mail")
		.overlay {
			if viewModel.threads.isEmpty {
				ContentUnavailableView(
					"No Messages",
					systemImage: "tray",
					description: Text("No threads in this mailbox")
				)
			}
		}
		.toolbar {
			folderToolbarItems
		}
	}

	// MARK: - Toolbar Items

	@ToolbarContentBuilder
	private var folderToolbarItems: some ToolbarContent {
		ToolbarItemGroup(placement: .automatic) {
			if viewModel.selectedThread != nil {
				Button {
					viewModel.archiveSelectedThread()
				} label: {
					Label("Archive", systemImage: "archivebox")
				}
				.keyboardShortcut("e", modifiers: [])
				.help("Archive (e)")

				Button {
					viewModel.deleteSelectedThread()
				} label: {
					Label("Delete", systemImage: "trash")
				}
				.keyboardShortcut(.delete, modifiers: [])
				.help("Delete (⌫)")

				Button {
					viewModel.toggleFlagSelectedThread()
				} label: {
					Label("Flag", systemImage: "flag")
				}
				.keyboardShortcut("s", modifiers: [])
				.help("Toggle Flag (s)")

				Button {
					viewModel.toggleReadSelectedThread()
				} label: {
					Label("Read/Unread", systemImage: "envelope.badge")
				}
				.keyboardShortcut("u", modifiers: [.shift, .command])
				.help("Toggle Read/Unread (⇧⌘U)")

				Button {
					showMoveSheet = true
				} label: {
					Label("Move", systemImage: "folder")
				}
				.keyboardShortcut("m", modifiers: [.shift, .command])
				.help("Move to… (⇧⌘M)")

				// GTD shortcuts available in folder views too
				Button {
					showDeferPicker = true
				} label: {
					Label("Defer", systemImage: "clock.arrow.circlepath")
				}
				.keyboardShortcut("d", modifiers: [])
				.help("Defer (d)")

				Button {
					showLabelPicker = true
				} label: {
					Label("Project", systemImage: "folder.badge.plus")
				}
				.keyboardShortcut("p", modifiers: [])
				.help("File to Project (p)")
			}
		}
	}

	@ToolbarContentBuilder
	private var gtdToolbarItems: some ToolbarContent {
		ToolbarItemGroup(placement: .automatic) {
			Button {
				showDeferPicker = true
			} label: {
				Label("Defer", systemImage: "clock.arrow.circlepath")
			}
			.keyboardShortcut("d", modifiers: [])
			.help("Defer (d)")

			Button {
				if let item = selectedItemSummary {
					viewModel.deferItem(item, until: nil)
				}
			} label: {
				Label("Someday", systemImage: "moon.zzz")
			}
			.keyboardShortcut("d", modifiers: [.shift])
			.help("Someday (⇧D)")

			Button {
				showLabelPicker = true
			} label: {
				Label("Project", systemImage: "folder.badge.plus")
			}
			.keyboardShortcut("p", modifiers: [])
			.help("File to Project (p)")

			Button {
				if let item = selectedItemSummary {
					viewModel.completeItem(item)
				}
			} label: {
				Label("Complete", systemImage: "checkmark.circle")
			}
			.keyboardShortcut(.return, modifiers: .command)
			.help("Complete (⌘⏎)")

			Button {
				if let item = selectedItemSummary {
					viewModel.discardItem(item)
				}
			} label: {
				Label("Discard", systemImage: "trash")
			}
			.keyboardShortcut(.delete, modifiers: [])
			.help("Discard (⌫)")
		}
	}

	// MARK: - Helpers

	private var selectedItemSummary: ItemSummary? {
		// In GTD mode, use the first item (or a future selection mechanism)
		// For now, if there's a selected thread, build the email item from it
		if let thread = viewModel.selectedThread,
		   let msg = viewModel.messages.first {
			return .email(msg)
		}
		return viewModel.items.first
	}

	private var availableLabels: [LabelInfo] {
		guard let store = viewModel.store, let config = viewModel.accountConfig else { return [] }
		let records = (try? store.labels(accountId: config.id)) ?? []
		return records.map { LabelInfo(id: $0.id, name: $0.name, isProject: $0.isProject, color: $0.color) }
	}

	private func createAndFileLabel(name: String) {
		guard let store = viewModel.store, let config = viewModel.accountConfig else { return }
		do {
			let labelId = UUID().uuidString
			let record = LabelRecord(
				id: labelId,
				accountId: config.id,
				name: name,
				isProject: true
			)
			try store.insertLabel(record)
			let label = LabelInfo(id: labelId, name: name, isProject: true)
			if let selectedItem = selectedItemSummary {
				viewModel.fileItem(selectedItem, label: label)
			}
		} catch {
			viewModel.errorMessage = error.localizedDescription
		}
	}
}

struct ItemRow: View {
	let item: ItemSummary

	var body: some View {
		HStack(spacing: 8) {
			switch item {
			case .email(let msg):
				Image(systemName: "envelope")
					.foregroundStyle(.blue)
				VStack(alignment: .leading, spacing: 2) {
					Text(msg.from?.displayName ?? "Unknown")
						.fontWeight(msg.isRead ? .regular : .bold)
						.lineLimit(1)
					Text(msg.subject ?? "(No Subject)")
						.font(.subheadline)
						.lineLimit(1)
					if let snippet = msg.snippet {
						Text(snippet)
							.font(.caption)
							.foregroundStyle(.tertiary)
							.lineLimit(1)
					}
				}

			case .task(let task):
				Image(systemName: task.status == .completed ? "checkmark.circle.fill" :
						task.status == .cancelled ? "xmark.circle" : "circle")
					.foregroundStyle(task.status == .completed ? .green :
						task.status == .cancelled ? .red : .primary)
				VStack(alignment: .leading, spacing: 2) {
					Text(task.summary)
						.fontWeight(.regular)
						.lineLimit(1)
						.strikethrough(task.status == .completed || task.status == .cancelled)
					if let due = task.dueDate {
						Text("Due \(due, style: .date)")
							.font(.caption)
							.foregroundStyle(due < Date() ? .red : .secondary)
					}
					if let desc = task.description {
						Text(desc)
							.font(.caption)
							.foregroundStyle(.tertiary)
							.lineLimit(1)
					}
				}
			}

			Spacer()

			Text(item.date, style: .relative)
				.font(.caption)
				.foregroundStyle(.secondary)
		}
		.padding(.vertical, 2)
	}
}

struct ThreadRow: View {
	let thread: ThreadSummary

	var body: some View {
		VStack(alignment: .leading, spacing: 4) {
			HStack {
				Text(thread.senders)
					.fontWeight(thread.unreadCount > 0 ? .bold : .regular)
					.lineLimit(1)
				Spacer()
				if thread.unreadCount > 0 {
					Circle()
						.fill(.blue)
						.frame(width: 8, height: 8)
				}
				Text(thread.lastDate, style: .relative)
					.font(.caption)
					.foregroundStyle(.secondary)
			}
			Text(thread.subject ?? "(No Subject)")
				.font(.subheadline)
				.lineLimit(1)
			if let snippet = thread.snippet {
				Text(snippet)
					.font(.caption)
					.foregroundStyle(.tertiary)
					.lineLimit(1)
			}
			if thread.messageCount > 1 {
				Text("\(thread.messageCount)")
					.font(.caption2)
					.foregroundStyle(.secondary)
					.padding(.horizontal, 6)
					.padding(.vertical, 1)
					.background(.quaternary, in: Capsule())
			}
		}
		.padding(.vertical, 2)
	}
}
