import { useEffect, useMemo, useState } from 'react';
import {
  CheckCheck,
  Info,
  Paperclip,
  Phone,
  Search,
  Send,
  Smile,
} from 'lucide-react';
import type { ChatMessageInterface } from '../../../mvvm/models/chat-message.interface';
import { MessagesViewModel, type MessageThreadItem } from '../../../mvvm/viewmodels/MessagesViewModel';
import { DashboardSidebar, type DashboardNavKey } from '../../dashboard/components/DashboardSidebar';
import { DashboardTopbar } from '../../dashboard/components/DashboardTopbar';
import '../../dashboard/pages/dashboard.css';
import './messages.css';

interface MessagesPageProps {
  onLogout: () => void;
  onNavigate: (target: DashboardNavKey) => void;
  onToggleTheme: () => void;
  theme: 'light' | 'dark';
}

type ThreadFilter = 'all' | 'unread' | 'companies';

function toMillis(value?: Date | string): number {
  if (!value) {
    return 0;
  }
  const date = value instanceof Date ? value : new Date(value);
  const millis = date.getTime();
  return Number.isNaN(millis) ? 0 : millis;
}

function formatTime(value?: Date | string): string {
  if (!value) {
    return '--:--';
  }
  const date = value instanceof Date ? value : new Date(value);
  if (Number.isNaN(date.getTime())) {
    return '--:--';
  }
  return new Intl.DateTimeFormat('da-DK', { hour: '2-digit', minute: '2-digit' }).format(date);
}

function formatThreadDate(value?: Date | string): string {
  if (!value) {
    return '';
  }
  const date = value instanceof Date ? value : new Date(value);
  if (Number.isNaN(date.getTime())) {
    return '';
  }

  const now = new Date();
  const dayMs = 24 * 60 * 60 * 1000;
  const diffDays = Math.floor((new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() - new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()) / dayMs);

  if (diffDays === 0) {
    return formatTime(date);
  }
  if (diffDays === 1) {
    return 'I går';
  }
  return new Intl.DateTimeFormat('da-DK', { day: '2-digit', month: 'short' }).format(date);
}

function dayLabel(value: Date): string {
  const now = new Date();
  const dateOnly = new Date(value.getFullYear(), value.getMonth(), value.getDate());
  const nowOnly = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const diff = Math.floor((nowOnly.getTime() - dateOnly.getTime()) / (24 * 60 * 60 * 1000));

  if (diff === 0) {
    return 'I dag';
  }
  if (diff === 1) {
    return 'I går';
  }
  return new Intl.DateTimeFormat('da-DK', { day: '2-digit', month: 'short' }).format(value);
}

function isUnreadMessage(message: ChatMessageInterface): boolean {
  return !message.fromCandidate && !message.seen;
}

function threadUnreadCount(thread: MessageThreadItem): number {
  return thread.allMessages.filter(isUnreadMessage).length;
}

function threadAvatar(thread: MessageThreadItem): string {
  return thread.companyLogoUrl || thread.companyLogo || '';
}

function normalizeThread(thread: MessageThreadItem): MessageThreadItem {
  return {
    ...thread,
    allMessages: [...(thread.allMessages ?? [])].sort((a, b) => toMillis(a.timeSent) - toMillis(b.timeSent)),
  };
}

function fallbackThreads(): MessageThreadItem[] {
  const now = new Date();
  const tenMinutesAgo = new Date(now.getTime() - 10 * 60 * 1000);
  const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);

  const makeMessage = (threadId: string, text: string, fromCandidate: boolean, when: Date, seen?: Date): ChatMessageInterface => ({
    threadId,
    text,
    fromCandidate,
    timeSent: when,
    seen,
  });

  const t1Messages = [
    makeMessage('thread-techcorp', 'Hej Lasse! Mange tak for din ansøgning.', false, twoHoursAgo),
    makeMessage('thread-techcorp', 'Mange tak, det lyder rigtig spændende.', true, new Date(twoHoursAgo.getTime() + 20 * 60 * 1000), new Date(twoHoursAgo.getTime() + 30 * 60 * 1000)),
    makeMessage('thread-techcorp', 'Vi vil gerne invitere dig til samtale.', false, tenMinutesAgo),
  ];

  const t2Messages = [
    makeMessage('thread-lunar', 'Mange tak for din opdaterede portefølje.', false, new Date(now.getTime() - 26 * 60 * 60 * 1000), new Date(now.getTime() - 25 * 60 * 60 * 1000)),
  ];

  return [
    {
      id: 'thread-techcorp',
      companyLogo: '',
      companyLogoUrl: 'https://i.pravatar.cc/150?img=33',
      companyName: 'TechCorp A/S',
      candidateFirstName: 'Lasse',
      candidateLastName: 'Hansen',
      candidateImage: 'https://i.pravatar.cc/150?img=11',
      allMessages: t1Messages,
      latestMessage: t1Messages[t1Messages.length - 1],
      title: 'Frontend Udvikler',
      messagesLoaded: true,
      jobPostingId: 'job-1',
      jobPosting: undefined as never,
      isFromSupport: false,
    },
    {
      id: 'thread-lunar',
      companyLogo: '',
      companyLogoUrl: 'https://i.pravatar.cc/150?img=12',
      companyName: 'Lunar Bank',
      candidateFirstName: 'Lasse',
      candidateLastName: 'Hansen',
      candidateImage: 'https://i.pravatar.cc/150?img=11',
      allMessages: t2Messages,
      latestMessage: t2Messages[t2Messages.length - 1],
      title: 'Senior UX Designer',
      messagesLoaded: true,
      jobPostingId: 'job-2',
      jobPosting: undefined as never,
      isFromSupport: false,
    },
  ];
}

export function MessagesPage({ onLogout, onNavigate, onToggleTheme, theme }: MessagesPageProps) {
  const viewModel = useMemo(() => new MessagesViewModel(), []);
  const [name, setName] = useState('Lasse');
  const [imageUrl, setImageUrl] = useState<string | undefined>(undefined);
  const [threads, setThreads] = useState<MessageThreadItem[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [filter, setFilter] = useState<ThreadFilter>('all');
  const [activeThreadId, setActiveThreadId] = useState<string>('');
  const [draft, setDraft] = useState('');

  useEffect(() => {
    let active = true;

    async function loadData() {
      setIsLoading(true);
      try {
        const profile = await viewModel.getCandidateProfile();
        if (active) {
          setName(profile.name);
          setImageUrl(profile.imageUrl);
        }

        const loadedThreads = await viewModel.getThreads();
        if (!active) {
          return;
        }
        const normalized = (loadedThreads.length > 0 ? loadedThreads : fallbackThreads()).map(normalizeThread);
        setThreads(normalized);
        setActiveThreadId(normalized[0]?.id || '');
      } catch {
        if (!active) {
          return;
        }
        const fallback = fallbackThreads();
        setThreads(fallback);
        setActiveThreadId(fallback[0]?.id || '');
      } finally {
        if (active) {
          setIsLoading(false);
        }
      }
    }
    void loadData();

    return () => {
      active = false;
    };
  }, [viewModel]);

  const filteredThreads = useMemo(() => {
    const term = search.trim().toLowerCase();

    return threads.filter((thread) => {
      if (filter === 'unread' && threadUnreadCount(thread) === 0) {
        return false;
      }
      if (filter === 'companies' && thread.isFromSupport) {
        return false;
      }
      if (!term) {
        return true;
      }
      return thread.companyName.toLowerCase().includes(term) || (thread.latestMessage?.text || '').toLowerCase().includes(term);
    });
  }, [filter, search, threads]);

  const activeThread = useMemo(
    () => threads.find((thread) => thread.id === activeThreadId) || filteredThreads[0],
    [activeThreadId, filteredThreads, threads],
  );

  const messages = useMemo(
    () => [...(activeThread?.allMessages || [])].sort((a, b) => toMillis(a.timeSent) - toMillis(b.timeSent)),
    [activeThread],
  );

  async function handleSelectThread(thread: MessageThreadItem) {
    setActiveThreadId(thread.id);
    const lastUnread = [...thread.allMessages].reverse().find((item) => isUnreadMessage(item));

    if (lastUnread?.id) {
      void viewModel.markThreadReadByMessageId(lastUnread.id);
      setThreads((current) => current.map((entry) => {
        if (entry.id !== thread.id) {
          return entry;
        }
        return {
          ...entry,
          allMessages: entry.allMessages.map((item) => (isUnreadMessage(item) ? { ...item, seen: new Date() } : item)),
        };
      }));
    }
  }

  async function handleMarkAllRead() {
    const latestUnread = threads
      .flatMap((thread) => thread.allMessages)
      .filter((item) => isUnreadMessage(item) && Boolean(item.id));

    await Promise.all(latestUnread.map((item) => viewModel.markThreadReadByMessageId(item.id)));
    setThreads((current) => current.map((thread) => ({
      ...thread,
      allMessages: thread.allMessages.map((item) => (isUnreadMessage(item) ? { ...item, seen: new Date() } : item)),
    })));
  }

  async function handleSendMessage() {
    const text = draft.trim();
    if (!activeThread || !text) {
      return;
    }

    const optimistic: ChatMessageInterface = {
      threadId: activeThread.id,
      text,
      fromCandidate: true,
      timeSent: new Date(),
    };

    setDraft('');
    setThreads((current) => current.map((thread) => {
      if (thread.id !== activeThread.id) {
        return thread;
      }
      const nextMessages = [...thread.allMessages, optimistic];
      return {
        ...thread,
        allMessages: nextMessages,
        latestMessage: optimistic,
      };
    }));

    try {
      const created = await viewModel.sendMessage(activeThread.id, text);
      setThreads((current) => current.map((thread) => {
        if (thread.id !== activeThread.id) {
          return thread;
        }
        const withoutOptimistic = thread.allMessages.filter((item) => item !== optimistic);
        const nextMessages = [...withoutOptimistic, created];
        return {
          ...thread,
          allMessages: nextMessages,
          latestMessage: created,
        };
      }));
    } catch {
      // Keep optimistic message visible if backend send fails.
    }
  }

  return (
    <section className={`dash-root ${theme === 'dark' ? 'theme-dark' : ''}`}>
      <div className="dash-orb dash-orb-1" />
      <div className="dash-orb dash-orb-2" />
      <div className="dash-orb dash-orb-3" />

      <DashboardSidebar active="messages" onNavigate={onNavigate} />

      <main className="dash-main custom-scrollbar msg-main">
        <DashboardTopbar
          name={name}
          imageUrl={imageUrl}
          onLogout={onLogout}
          theme={theme}
          onToggleTheme={onToggleTheme}
        />

        <div className="msg-head">
          <div>
            <h1>Beskeder</h1>
            <p>Kommuniker med virksomheder og hold styr på dine ansøgninger.</p>
          </div>
          <button type="button" className="msg-mark-btn" onClick={() => void handleMarkAllRead()}>
            <CheckCheck size={16} strokeWidth={1.8} /> Marker alle som læst
          </button>
        </div>

        <div className="msg-layout">
          <section className="msg-threads">
            <div className="msg-threads-head">
              <div className="msg-search-wrap">
                <Search size={16} strokeWidth={1.8} />
                <input value={search} onChange={(event) => setSearch(event.target.value)} type="text" placeholder="Søg i beskeder..." />
              </div>
              <div className="msg-filter-row">
                <button type="button" className={filter === 'all' ? 'active' : ''} onClick={() => setFilter('all')}>Alle</button>
                <button type="button" className={filter === 'unread' ? 'active' : ''} onClick={() => setFilter('unread')}>Ulæste</button>
                <button type="button" className={filter === 'companies' ? 'active' : ''} onClick={() => setFilter('companies')}>Virksomheder</button>
              </div>
            </div>

            <div className="msg-thread-list custom-scrollbar">
              {isLoading ? <p className="dash-loading">Indlaeser beskeder...</p> : null}
              {!isLoading && filteredThreads.length === 0 ? <p className="dash-loading">Ingen tråde fundet.</p> : null}

              {filteredThreads.map((thread) => {
                const unread = threadUnreadCount(thread);
                const isActive = activeThread?.id === thread.id;
                const avatar = threadAvatar(thread);

                return (
                  <button type="button" key={thread.id} className={isActive ? 'msg-thread-item active' : 'msg-thread-item'} onClick={() => void handleSelectThread(thread)}>
                    <div className="msg-thread-avatar-wrap">
                      {avatar ? <img src={avatar} alt={thread.companyName} className="msg-thread-avatar" /> : <div className="msg-thread-avatar-fallback">{thread.companyName.slice(0, 1).toUpperCase()}</div>}
                      <span className="msg-thread-online" />
                    </div>
                    <div className="msg-thread-content">
                      <div className="msg-thread-row">
                        <h3>{thread.companyName}</h3>
                        <span>{formatThreadDate(thread.latestMessage?.timeSent)}</span>
                      </div>
                      <p className={unread > 0 ? 'unread' : ''}>{thread.latestMessage?.text || 'Ingen beskeder endnu'}</p>
                      <small>{thread.title || 'Stilling'}</small>
                    </div>
                    {unread > 0 ? <div className="msg-thread-unread">{unread}</div> : null}
                  </button>
                );
              })}
            </div>
          </section>

          <section className="msg-chat">
            <div className="msg-chat-head">
              {activeThread ? (
                <>
                  <div className="msg-chat-company">
                    {threadAvatar(activeThread)
                      ? <img src={threadAvatar(activeThread)} alt={activeThread.companyName} className="msg-chat-avatar" />
                      : <div className="msg-chat-avatar-fallback">{activeThread.companyName.slice(0, 1).toUpperCase()}</div>}
                    <div>
                      <h2>{activeThread.companyName}</h2>
                      <p>{activeThread.title || 'Rekruttering'}</p>
                    </div>
                  </div>
                  <div className="msg-chat-actions">
                    <button type="button" aria-label="Ring"><Phone size={16} strokeWidth={1.8} /></button>
                    <button type="button" aria-label="Info"><Info size={16} strokeWidth={1.8} /></button>
                  </div>
                </>
              ) : (
                <h2>Vælg en samtale</h2>
              )}
            </div>

            <div className="msg-chat-body custom-scrollbar">
              {messages.map((message, index) => {
                const currentTime = message.timeSent instanceof Date ? message.timeSent : new Date(message.timeSent);
                const prev = index > 0 ? messages[index - 1] : undefined;
                const prevTime = prev?.timeSent instanceof Date ? prev.timeSent : (prev?.timeSent ? new Date(prev.timeSent) : undefined);
                const showDay = !prevTime || currentTime.toDateString() !== prevTime.toDateString();

                return (
                  <div key={`${message.threadId}-${index}`}>
                    {showDay ? <div className="msg-day-sep">{dayLabel(currentTime)}</div> : null}
                    <div className={message.fromCandidate ? 'msg-bubble-row mine' : 'msg-bubble-row'}>
                      {!message.fromCandidate ? (
                        threadAvatar(activeThread as MessageThreadItem)
                          ? <img src={threadAvatar(activeThread as MessageThreadItem)} alt={(activeThread as MessageThreadItem).companyName} className="msg-mini-avatar" />
                          : <div className="msg-mini-avatar msg-mini-avatar-fallback">{(activeThread as MessageThreadItem).companyName.slice(0, 1).toUpperCase()}</div>
                      ) : null}

                      <div className="msg-bubble-wrap">
                        <span className="msg-time">{formatTime(message.timeSent)}</span>
                        <div className={message.fromCandidate ? 'msg-bubble mine' : 'msg-bubble'}>{message.text}</div>
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>

            <div className="msg-input-area">
              <div className="msg-input-wrap">
                <button type="button" aria-label="Vedhæft"><Paperclip size={18} strokeWidth={1.8} /></button>
                <textarea
                  rows={1}
                  value={draft}
                  onChange={(event) => setDraft(event.target.value)}
                  onKeyDown={(event) => {
                    if (event.key === 'Enter' && !event.shiftKey) {
                      event.preventDefault();
                      void handleSendMessage();
                    }
                  }}
                  placeholder="Skriv din besked her..."
                />
                <button type="button" aria-label="Emoji"><Smile size={18} strokeWidth={1.8} /></button>
                <button type="button" className="msg-send-btn" onClick={() => void handleSendMessage()}>
                  Send <Send size={15} strokeWidth={1.8} />
                </button>
              </div>
            </div>
          </section>
        </div>
      </main>
    </section>
  );
}
