import Testing
import GRDB
@testable import MailStore

@Suite("MailStore CRUD")
struct MailStoreTests {
	func makeStore() throws -> MailStore {
		try MailStore(dbWriter: DatabaseSetup.openInMemoryDatabase())
	}

	@Test("insert and retrieve account")
	func accountCRUD() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		let accounts = try store.accounts()
		#expect(accounts.count == 1)
		#expect(accounts[0].name == "Personal")
	}

	@Test("insert and retrieve mailbox")
	func mailboxCRUD() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		try store.upsertMailbox(MailboxRecord(
			id: "mb1", accountId: "acc1", name: "INBOX", uidValidity: 1, uidNext: 100
		))
		let mailboxes = try store.mailboxes(accountId: "acc1")
		#expect(mailboxes.count == 1)
		#expect(mailboxes[0].name == "INBOX")
	}

	@Test("insert and retrieve messages")
	func messageCRUD() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		try store.upsertMailbox(MailboxRecord(
			id: "mb1", accountId: "acc1", name: "INBOX", uidValidity: 1, uidNext: 100
		))
		try store.insertMessages([
			MessageRecord(
				id: "m1", accountId: "acc1", mailboxId: "mb1", uid: 1,
				messageId: "msg001@example.com", inReplyTo: nil, refs: nil,
				subject: "Hello", fromAddress: "alice@example.com", fromName: "Alice",
				toAddresses: "[{\"address\":\"user@example.com\"}]", ccAddresses: nil,
				date: "2024-03-08T10:15:32Z", snippet: "Hi there",
				bodyText: nil, bodyHtml: nil,
				isRead: false, isFlagged: false, size: 1024
			),
		])
		let messages = try store.messages(mailboxId: "mb1")
		#expect(messages.count == 1)
		#expect(messages[0].subject == "Hello")
	}

	@Test("update mailbox uidNext")
	func updateMailboxUidNext() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		try store.upsertMailbox(MailboxRecord(
			id: "mb1", accountId: "acc1", name: "INBOX", uidValidity: 1, uidNext: 100
		))
		try store.updateMailboxSync(id: "mb1", uidValidity: 1, uidNext: 150)
		let mailboxes = try store.mailboxes(accountId: "acc1")
		#expect(mailboxes[0].uidNext == 150)
	}

	@Test("update message flags")
	func updateFlags() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		try store.upsertMailbox(MailboxRecord(
			id: "mb1", accountId: "acc1", name: "INBOX", uidValidity: 1, uidNext: 100
		))
		try store.insertMessages([
			MessageRecord(
				id: "m1", accountId: "acc1", mailboxId: "mb1", uid: 1,
				messageId: nil, inReplyTo: nil, refs: nil,
				subject: "Test", fromAddress: nil, fromName: nil,
				toAddresses: nil, ccAddresses: nil,
				date: "2024-03-08T10:15:32Z", snippet: nil,
				bodyText: nil, bodyHtml: nil,
				isRead: false, isFlagged: false, size: 0
			),
		])
		try store.updateFlags(messageId: "m1", isRead: true, isFlagged: true)
		let messages = try store.messages(mailboxId: "mb1")
		#expect(messages[0].isRead == true)
		#expect(messages[0].isFlagged == true)
	}

	@Test("store body text and html")
	func storeBody() throws {
		let store = try makeStore()
		try store.insertAccount(AccountRecord(
			id: "acc1", name: "Personal", email: "user@example.com",
			imapHost: "imap.example.com", imapPort: 993
		))
		try store.upsertMailbox(MailboxRecord(
			id: "mb1", accountId: "acc1", name: "INBOX", uidValidity: 1, uidNext: 100
		))
		try store.insertMessages([
			MessageRecord(
				id: "m1", accountId: "acc1", mailboxId: "mb1", uid: 1,
				messageId: nil, inReplyTo: nil, refs: nil,
				subject: "Test", fromAddress: nil, fromName: nil,
				toAddresses: nil, ccAddresses: nil,
				date: "2024-03-08T10:15:32Z", snippet: nil,
				bodyText: nil, bodyHtml: nil,
				isRead: false, isFlagged: false, size: 0
			),
		])
		try store.storeBody(messageId: "m1", text: "Plain text body", html: "<p>HTML body</p>")
		let msg = try store.message(id: "m1")
		#expect(msg?.bodyText == "Plain text body")
		#expect(msg?.bodyHtml == "<p>HTML body</p>")
	}
}
