import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js";
import { useParams } from "@solidjs/router";
import { RefreshCcw, Send, ServerCog, Plus } from "lucide-solid";

import {
  apiConnectMailbox,
  apiCreateOutgoingMail,
  apiCreateTaskFromMail,
  apiListMailMessages,
  apiListMailboxes,
  apiListOutgoingMails,
  apiSyncMailbox
} from "~/lib/api";
import { useApp } from "~/lib/app-context";
import type { MailAddress, MailMessage, Mailbox, OutgoingMail } from "~/lib/types";
import { formatPrettyDate } from "~/lib/utils";

const emptyConnectForm = {
  label: "",
  email: "",
  displayName: "",
  imapHost: "",
  imapPort: 993,
  imapUsername: "",
  imapPassword: "",
  imapUseTls: true,
  smtpHost: "",
  smtpPort: 587,
  smtpUsername: "",
  smtpPassword: "",
  smtpUseTls: true
};

const emptyComposeForm = {
  to: "",
  cc: "",
  bcc: "",
  subject: "",
  textBody: "",
  htmlBody: "",
  scheduledFor: ""
};

export default function MailRoute() {
  const app = useApp();
  const params = useParams();
  const workspaceSlug = () => params.workspaceSlug || app.primaryWorkspace()?.slug || "personal";

  const [loading, setLoading] = createSignal(true);
  const [savingMailbox, setSavingMailbox] = createSignal(false);
  const [sendingMail, setSendingMail] = createSignal(false);
  const [status, setStatus] = createSignal("");
  const [mailboxes, setMailboxes] = createSignal<Mailbox[]>([]);
  const [messages, setMessages] = createSignal<MailMessage[]>([]);
  const [outgoing, setOutgoing] = createSignal<OutgoingMail[]>([]);
  const [selectedMailboxId, setSelectedMailboxId] = createSignal("");
  const [selectedMessageId, setSelectedMessageId] = createSignal("");
  const [taskBoardGroupId, setTaskBoardGroupId] = createSignal("group-inbox");
  const [connectForm, setConnectForm] = createSignal(emptyConnectForm);
  const [composeForm, setComposeForm] = createSignal(emptyComposeForm);
  const [showConnect, setShowConnect] = createSignal(false);
  const [showCompose, setShowCompose] = createSignal(false);

  const workspaceBoardGroups = createMemo(() =>
    app.state.boardGroups.filter(group => group.workspaceSlug === workspaceSlug()),
  );
  const selectedMessage = createMemo(() => messages().find(message => message.id === selectedMessageId()));
  createEffect(() => {
    const groups = workspaceBoardGroups();
    if (!groups.length) return;
    if (!groups.some(group => group.id === taskBoardGroupId())) {
      setTaskBoardGroupId(groups[0].id);
    }
  });

  onMount(() => {
    void loadMailData();
  });

  async function loadMailData(preferredMailboxId?: string) {
    setLoading(true);
    try {
      const nextMailboxes = await apiListMailboxes(workspaceSlug());
      setMailboxes(nextMailboxes);
      const mailboxId = preferredMailboxId || selectedMailboxId() || nextMailboxes[0]?.id || "";
      setSelectedMailboxId(mailboxId);
      const [nextMessages, nextOutgoing] = await Promise.all([
        apiListMailMessages(workspaceSlug(), mailboxId || undefined),
        apiListOutgoingMails(workspaceSlug(), mailboxId || undefined)
      ]);
      setMessages(nextMessages);
      setOutgoing(nextOutgoing);
      if (!nextMessages.some(message => message.id === selectedMessageId())) {
        setSelectedMessageId(nextMessages[0]?.id ?? "");
      }
      setStatus("");
    } catch (error) {
      setStatus(errorMessage(error));
    } finally {
      setLoading(false);
    }
  }

  async function connectMailbox() {
    setSavingMailbox(true);
    setStatus("");
    try {
      const created = await apiConnectMailbox({
        workspaceSlug: workspaceSlug(),
        ...connectForm()
      });
      setConnectForm(emptyConnectForm);
      setShowConnect(false);
      await loadMailData(created?.id);
      setStatus(created ? `Connected ${created.email}.` : "Mailbox connected.");
    } catch (error) {
      setStatus(errorMessage(error));
    } finally {
      setSavingMailbox(false);
    }
  }

  async function syncMailbox() {
    if (!selectedMailboxId()) return;
    setStatus("");
    try {
      await apiSyncMailbox(selectedMailboxId());
      await loadMailData(selectedMailboxId());
      setStatus("Mailbox synced.");
    } catch (error) {
      setStatus(errorMessage(error));
    }
  }

  async function sendMail() {
    if (!selectedMailboxId()) {
      setStatus("Connect a mailbox before sending mail.");
      return;
    }

    setSendingMail(true);
    setStatus("");
    try {
      await apiCreateOutgoingMail({
        workspaceSlug: workspaceSlug(),
        mailboxId: selectedMailboxId(),
        to: parseAddressList(composeForm().to),
        cc: parseAddressList(composeForm().cc),
        bcc: parseAddressList(composeForm().bcc),
        subject: composeForm().subject,
        textBody: composeForm().textBody,
        htmlBody: composeForm().htmlBody,
        scheduledFor: composeForm().scheduledFor ? new Date(composeForm().scheduledFor).toISOString() : undefined
      });
      setComposeForm(emptyComposeForm);
      setShowCompose(false);
      await loadMailData(selectedMailboxId());
      setStatus("Outgoing mail queued.");
    } catch (error) {
      setStatus(errorMessage(error));
    } finally {
      setSendingMail(false);
    }
  }

  async function createTaskFromMessage() {
    const message = selectedMessage();
    if (!message) return;

    setStatus("");
    try {
      await apiCreateTaskFromMail(message.id, {
        boardGroupId: taskBoardGroupId(),
        title: message.subject
      });
      await loadMailData(selectedMailboxId());
      setStatus("Task created from mail.");
    } catch (error) {
      setStatus(errorMessage(error));
    }
  }

  return (
    <div class="flex h-full gap-4">
      {/* Sidebar: Mailboxes */}
      <aside class="w-56 shrink-0 space-y-4">
        <div class="rounded-lg border border-[var(--border)] bg-[var(--surface)]">
          <div class="border-b border-[var(--border)] p-3">
            <div class="flex items-center justify-between">
              <h1 class="text-sm font-semibold">Mail</h1>
              <button
                class="flex h-6 w-6 items-center justify-center rounded text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-subtle)] hover:text-[var(--text)]"
                onClick={() => setShowConnect(!showConnect())}
                aria-label="Add mailbox"
              >
                <Plus size={14} />
              </button>
            </div>
          </div>
          <div class="divide-y divide-[var(--border)]">
            <For each={mailboxes()}>
              {mailbox => (
                <button
                  class="w-full px-3 py-2 text-left transition-colors"
                  classList={{
                    "bg-[var(--accent-subtle)]": mailbox.id === selectedMailboxId(),
                    "hover:bg-[var(--bg-subtle)]": mailbox.id !== selectedMailboxId()
                  }}
                  onClick={() => {
                    setSelectedMailboxId(mailbox.id);
                    void loadMailData(mailbox.id);
                  }}
                >
                  <p class="truncate text-sm font-medium">{mailbox.label}</p>
                  <p class="truncate text-xs text-[var(--text-muted)]">{mailbox.email}</p>
                </button>
              )}
            </For>
            <Show when={mailboxes().length === 0}>
              <div class="px-3 py-4 text-center text-xs text-[var(--text-muted)]">
                No mailboxes
              </div>
            </Show>
          </div>
        </div>

        {/* Actions */}
        <div class="space-y-2">
          <button
            class="button-secondary flex w-full items-center justify-center gap-2 px-3 py-2 text-xs"
            onClick={() => void loadMailData(selectedMailboxId())}
          >
            <RefreshCcw size={12} />
            Refresh
          </button>
          <button
            class="button-secondary flex w-full items-center justify-center gap-2 px-3 py-2 text-xs"
            onClick={syncMailbox}
            disabled={!selectedMailboxId()}
          >
            <ServerCog size={12} />
            Sync
          </button>
          <button
            class="button-primary flex w-full items-center justify-center gap-2 px-3 py-2 text-xs"
            onClick={() => setShowCompose(true)}
            disabled={!selectedMailboxId()}
          >
            <Send size={12} />
            Compose
          </button>
        </div>

        {/* Status */}
        <Show when={status()}>
          <div class="rounded-md bg-[var(--bg-subtle)] px-3 py-2 text-xs text-[var(--text-muted)]">
            {status()}
          </div>
        </Show>
      </aside>

      {/* Message list */}
      <div class="w-80 shrink-0 rounded-lg border border-[var(--border)] bg-[var(--surface)]">
        <div class="border-b border-[var(--border)] px-3 py-2">
          <h2 class="text-sm font-medium">Inbox</h2>
        </div>
        <div class="divide-y divide-[var(--border)] overflow-y-auto">
          <Show when={loading()}>
            <div class="px-3 py-4 text-center text-sm text-[var(--text-muted)]">Loading...</div>
          </Show>
          <Show when={!loading() && messages().length === 0}>
            <div class="px-3 py-8 text-center text-sm text-[var(--text-muted)]">
              No messages
            </div>
          </Show>
          <For each={messages()}>
            {message => (
              <button
                class="w-full px-3 py-2 text-left transition-colors"
                classList={{
                  "bg-[var(--accent-subtle)]": message.id === selectedMessageId(),
                  "hover:bg-[var(--bg-subtle)]": message.id !== selectedMessageId()
                }}
                onClick={() => setSelectedMessageId(message.id)}
              >
                <p class="truncate text-sm font-medium">{message.subject || "(no subject)"}</p>
                <p class="truncate text-xs text-[var(--text-muted)]">
                  {message.from.name || message.from.email}
                </p>
                <p class="mt-1 text-xs text-[var(--text-subtle)]">
                  {formatPrettyDate(message.receivedAt)}
                </p>
              </button>
            )}
          </For>
        </div>
      </div>

      {/* Message detail */}
      <div class="flex-1 rounded-lg border border-[var(--border)] bg-[var(--surface)]">
        <Show
          when={selectedMessage()}
          fallback={
            <div class="flex h-full items-center justify-center text-sm text-[var(--text-muted)]">
              Select a message to view
            </div>
          }
        >
          {message => (
            <div class="flex h-full flex-col">
              {/* Header */}
              <div class="border-b border-[var(--border)] px-4 py-3">
                <h3 class="text-sm font-semibold">{message().subject || "(no subject)"}</h3>
                <p class="mt-1 text-xs text-[var(--text-muted)]">
                  From: {message().from.name ? `${message().from.name} <${message().from.email}>` : message().from.email}
                </p>
                <p class="text-xs text-[var(--text-muted)]">
                  To: {message().to.map(a => a.email).join(", ")}
                </p>
              </div>

              {/* Body */}
              <div class="flex-1 overflow-y-auto p-4">
                <pre class="whitespace-pre-wrap text-sm text-[var(--text-muted)]">
                  {message().textBody || message().snippet}
                </pre>
              </div>

              {/* Actions */}
              <div class="border-t border-[var(--border)] px-4 py-3">
                <div class="flex items-center gap-2">
                  <select
                    class="input-base h-8 text-xs"
                    value={taskBoardGroupId()}
                    onInput={event => setTaskBoardGroupId(event.currentTarget.value)}
                  >
                    <For each={workspaceBoardGroups()}>
                      {group => <option value={group.id}>{group.name}</option>}
                    </For>
                  </select>
                  <button
                    class="button-secondary px-3 py-1.5 text-xs"
                    onClick={createTaskFromMessage}
                    disabled={Boolean(message().linkedTaskId)}
                  >
                    {message().linkedTaskId ? "Task linked" : "Create task"}
                  </button>
                </div>
              </div>
            </div>
          )}
        </Show>
      </div>

      {/* Connect mailbox modal */}
      <Show when={showConnect()}>
        <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={() => setShowConnect(false)}>
          <div class="w-full max-w-lg rounded-lg border border-[var(--border)] bg-[var(--surface)] p-4" onClick={e => e.stopPropagation()}>
            <h3 class="mb-4 text-sm font-semibold">Connect Mailbox</h3>
            <div class="grid gap-2 text-xs">
              <input class="input-base" placeholder="Label" value={connectForm().label} onInput={event => setConnectForm(form => ({ ...form, label: event.currentTarget.value }))} />
              <input class="input-base" placeholder="Email" value={connectForm().email} onInput={event => setConnectForm(form => ({ ...form, email: event.currentTarget.value }))} />
              <input class="input-base" placeholder="IMAP host" value={connectForm().imapHost} onInput={event => setConnectForm(form => ({ ...form, imapHost: event.currentTarget.value }))} />
              <input class="input-base" placeholder="IMAP username" value={connectForm().imapUsername} onInput={event => setConnectForm(form => ({ ...form, imapUsername: event.currentTarget.value }))} />
              <input class="input-base" type="password" placeholder="IMAP password" value={connectForm().imapPassword} onInput={event => setConnectForm(form => ({ ...form, imapPassword: event.currentTarget.value }))} />
              <input class="input-base" placeholder="SMTP host" value={connectForm().smtpHost} onInput={event => setConnectForm(form => ({ ...form, smtpHost: event.currentTarget.value }))} />
              <input class="input-base" type="password" placeholder="SMTP password (optional)" value={connectForm().smtpPassword} onInput={event => setConnectForm(form => ({ ...form, smtpPassword: event.currentTarget.value }))} />
            </div>
            <div class="mt-4 flex justify-end gap-2">
              <button class="button-secondary px-3 py-1.5 text-xs" onClick={() => setShowConnect(false)}>Cancel</button>
              <button class="button-primary px-3 py-1.5 text-xs" onClick={connectMailbox} disabled={savingMailbox()}>
                {savingMailbox() ? "Connecting..." : "Connect"}
              </button>
            </div>
          </div>
        </div>
      </Show>

      {/* Compose modal */}
      <Show when={showCompose()}>
        <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={() => setShowCompose(false)}>
          <div class="w-full max-w-lg rounded-lg border border-[var(--border)] bg-[var(--surface)] p-4" onClick={e => e.stopPropagation()}>
            <h3 class="mb-4 text-sm font-semibold">Compose</h3>
            <div class="grid gap-2 text-xs">
              <input class="input-base" placeholder="To" value={composeForm().to} onInput={event => setComposeForm(form => ({ ...form, to: event.currentTarget.value }))} />
              <input class="input-base" placeholder="Subject" value={composeForm().subject} onInput={event => setComposeForm(form => ({ ...form, subject: event.currentTarget.value }))} />
              <textarea class="input-base min-h-32" placeholder="Message" value={composeForm().textBody} onInput={event => setComposeForm(form => ({ ...form, textBody: event.currentTarget.value }))} />
            </div>
            <div class="mt-4 flex justify-end gap-2">
              <button class="button-secondary px-3 py-1.5 text-xs" onClick={() => setShowCompose(false)}>Cancel</button>
              <button class="button-primary px-3 py-1.5 text-xs" onClick={sendMail} disabled={sendingMail()}>
                {sendingMail() ? "Sending..." : "Send"}
              </button>
            </div>
          </div>
        </div>
      </Show>
    </div>
  );
}

function parseAddressList(value: string): MailAddress[] {
  return value
    .split(",")
    .map(item => item.trim())
    .filter(Boolean)
    .map(item => {
      const match = item.match(/^(.*)<([^>]+)>$/);
      if (!match) {
        return { name: "", email: item };
      }
      return {
        name: match[1].trim().replace(/^"|"$/g, ""),
        email: match[2].trim()
      };
    });
}

function errorMessage(error: unknown) {
  if (error instanceof Error) {
    return error.message;
  }
  return "Mail action failed.";
}
