import type { FormEvent } from 'react';
import { useMemo, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { Loader2, MessageSquare, Send } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { ModuleHeader } from '@/components/ui/module-header';
import { PageSkeleton } from '@/components/ui/page-skeleton';
import {
  getDirectContacts,
  getDirectConversations,
  getDirectThread,
  sendDirectMessage,
  type DirectContact,
  type DirectConversation,
} from '@/business/direct-messages/api';
import { getErrorMessage } from '@/shared/errors/errorMessages';
import { cn } from '@/lib/utils';

export default function MessagesPage() {
  const queryClient = useQueryClient();
  const [selectedTarget, setSelectedTarget] = useState<{
    readonly conversationKey: string;
    readonly userId: string;
    readonly studentId: string | null;
  } | null>(null);
  const [text, setText] = useState('');
  const [sending, setSending] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const conversationsQuery = useQuery({
    queryKey: ['dm-conversations'],
    queryFn: getDirectConversations,
  });
  const contactsQuery = useQuery({ queryKey: ['dm-contacts'], queryFn: getDirectContacts });
  const threadQuery = useQuery({
    queryKey: ['dm-thread', selectedTarget?.userId, selectedTarget?.studentId],
    queryFn: () => getDirectThread(
      selectedTarget?.userId ?? '',
      selectedTarget?.studentId ?? null,
    ),
    enabled: Boolean(selectedTarget),
  });

  const conversations = useMemo(
    () => conversationsQuery.data?.rows ?? [],
    [conversationsQuery.data],
  );
  const contacts = useMemo(
    () => contactsQuery.data?.rows ?? [],
    [contactsQuery.data],
  );

  // Contacts you don't already have a conversation with (to start a new chat).
  const newContacts = useMemo(() => {
    const existing = new Set(conversations.map((c) => c.conversationKey));
    return contacts.filter((c) => !existing.has(c.conversationKey));
  }, [contacts, conversations]);

  function openContact(contact: DirectContact) {
    setSelectedTarget({
      conversationKey: contact.conversationKey,
      userId: contact.userId,
      studentId: contact.studentId,
    });
    setError(null);
  }

  function openConversation(conversation: DirectConversation) {
    setSelectedTarget({
      conversationKey: conversation.conversationKey,
      userId: conversation.userId,
      studentId: conversation.studentId,
    });
    setError(null);
  }

  async function handleSend(event: FormEvent) {
    event.preventDefault();
    if (!selectedTarget || !text.trim()) return;
    setError(null);
    setSending(true);
    try {
      await sendDirectMessage(
        selectedTarget.userId,
        text.trim(),
        selectedTarget.studentId ?? undefined,
      );
      setText('');
      await Promise.all([
        queryClient.invalidateQueries({
          queryKey: ['dm-thread', selectedTarget.userId, selectedTarget.studentId],
        }),
        queryClient.invalidateQueries({ queryKey: ['dm-conversations'] }),
      ]);
    } catch (err) {
      setError(getErrorMessage(err, 'Could not send message'));
    } finally {
      setSending(false);
    }
  }

  if (conversationsQuery.isLoading || contactsQuery.isLoading) {
    return <PageSkeleton />;
  }

  const otherName =
    threadQuery.data?.other?.name ??
    conversations.find((c) => c.conversationKey === selectedTarget?.conversationKey)?.name ??
    contacts.find((c) => c.conversationKey === selectedTarget?.conversationKey)?.name ??
    '';
  const studentName =
    threadQuery.data?.other?.studentName ??
    conversations.find((c) => c.conversationKey === selectedTarget?.conversationKey)?.studentName ??
    contacts.find((c) => c.conversationKey === selectedTarget?.conversationKey)?.studentName ??
    null;

  return (
    <div className="space-y-6 p-4 md:p-6">
      <ModuleHeader
        title="Messages"
        description="Private conversations between staff and guardians."
        icon={MessageSquare}
        iconClassName="bg-gradient-to-br from-cyan-500 to-cyan-700"
      />

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
        <Card className="lg:col-span-1">
          <CardHeader>
            <CardTitle className="text-base">Conversations</CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            {conversations.length === 0 ? (
              <p className="text-sm text-slate-400">No conversations yet.</p>
            ) : (
              <ul className="space-y-1">
                {conversations.map((c) => (
                  <li key={c.conversationKey}>
                    <button
                      type="button"
                      onClick={() => openConversation(c)}
                      className={cn(
                        'w-full rounded-lg px-3 py-2 text-left transition-colors',
                        selectedTarget?.conversationKey === c.conversationKey
                          ? 'bg-slate-700/60'
                          : 'hover:bg-slate-800/50',
                      )}
                    >
                      <div className="flex items-center justify-between">
                        <span className="text-sm font-medium text-slate-200">{c.name}</span>
                        {c.unread > 0 && (
                          <span className="rounded-full bg-cyan-500 px-1.5 text-[10px] font-bold text-white">
                            {c.unread}
                          </span>
                        )}
                      </div>
                      {c.studentName && (
                        <p className="truncate text-xs text-slate-400">re: {c.studentName}</p>
                      )}
                      <p className="truncate text-xs text-slate-500">{c.lastMessage}</p>
                    </button>
                  </li>
                ))}
              </ul>
            )}

            {newContacts.length > 0 && (
              <div>
                <p className="mb-1 text-xs font-semibold text-slate-400">Start a new chat</p>
                <ul className="space-y-1">
                  {newContacts.map((c) => (
                    <li key={c.conversationKey}>
                      <button
                        type="button"
                        onClick={() => openContact(c)}
                        className={cn(
                          'w-full rounded-lg px-3 py-2 text-left transition-colors',
                          selectedTarget?.conversationKey === c.conversationKey
                            ? 'bg-slate-700/60'
                            : 'hover:bg-slate-800/50',
                        )}
                      >
                        <span className="text-sm text-slate-200">{c.name}</span>
                        {c.studentName && (
                          <p className="text-xs text-slate-500">re: {c.studentName}</p>
                        )}
                      </button>
                    </li>
                  ))}
                </ul>
              </div>
            )}
          </CardContent>
        </Card>

        <Card className="lg:col-span-2">
          <CardHeader>
            <CardTitle className="text-base">
              {otherName || 'Select a conversation'}
              {studentName && (
                <span className="ml-2 text-xs font-normal text-slate-400">re: {studentName}</span>
              )}
            </CardTitle>
          </CardHeader>
          <CardContent>
            {!selectedTarget ? (
              <p className="text-sm text-slate-400">
                Choose a conversation or a contact to start messaging.
              </p>
            ) : (
              <div className="flex h-[28rem] flex-col">
                <div className="flex-1 space-y-2 overflow-y-auto pr-1">
                  {(threadQuery.data?.rows ?? []).length === 0 ? (
                    <p className="text-sm text-slate-400">No messages yet. Say hello.</p>
                  ) : (
                    (threadQuery.data?.rows ?? []).map((m) => (
                      <div
                        key={m.id}
                        className={cn('flex', m.mine ? 'justify-end' : 'justify-start')}
                      >
                        <div
                          className={cn(
                            'max-w-[75%] rounded-2xl px-3 py-2 text-sm',
                            m.mine
                              ? 'bg-cyan-600 text-white'
                              : 'bg-slate-700/60 text-slate-100',
                          )}
                        >
                          {m.body}
                        </div>
                      </div>
                    ))
                  )}
                </div>

                {error && <p className="mt-2 text-xs text-red-400">{error}</p>}

                <form className="mt-3 flex items-center gap-2" onSubmit={handleSend}>
                  <Input
                    value={text}
                    onChange={(e) => setText(e.target.value)}
                    placeholder="Type a message…"
                  />
                  <Button type="submit" size="icon" disabled={sending || !text.trim()}>
                    {sending ? <Loader2 size={16} className="animate-spin" /> : <Send size={16} />}
                  </Button>
                </form>
              </div>
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  );
}
