import { useEffect, useMemo, useState } from 'preact/hooks';
import {
  MindforgeApiService,
  type FlashcardCard,
  type FlashcardRagDashboardResponse,
  type FlashcardRagLibrary,
  type FlashcardRagStatus,
} from '../services/MindforgeApiService';
import { Button } from './Button';
import './SpacedReviewComponent.css';

interface RagStatusOption {
  status: FlashcardRagStatus;
  label: string;
  icon: string;
}

interface RagStatusMeta {
  label: string;
  icon: string;
  className: string;
}

const STATUS_OPTIONS: RagStatusOption[] = [
  { status: 'Red', label: 'Vermelho', icon: '!' },
  { status: 'Amber', label: 'Amarelo', icon: '*' },
  { status: 'Green', label: 'Verde', icon: 'v' },
  { status: 'Grey', label: 'Cinza', icon: '-' },
];

const STATUS_META_BY_STATUS: Record<FlashcardRagStatus, RagStatusMeta> = {
  Red: { label: 'Vermelho', icon: '!', className: 'rag-red' },
  Amber: { label: 'Amarelo', icon: '*', className: 'rag-amber' },
  Green: { label: 'Verde', icon: 'v', className: 'rag-green' },
  Grey: { label: 'Cinza', icon: '-', className: 'rag-grey' },
};

const STATUS_PRIORITY: Record<FlashcardRagStatus, number> = {
  Red: 0,
  Amber: 1,
  Green: 2,
  Grey: 3,
};

function shuffleCards(cards: FlashcardCard[]) {
  const shuffled = [...cards];

  for (let index = shuffled.length - 1; index > 0; index--) {
    const randomIndex = Math.floor(Math.random() * (index + 1));
    [shuffled[index], shuffled[randomIndex]] = [shuffled[randomIndex], shuffled[index]];
  }

  return shuffled;
}

function formatPercentage(value: number) {
  return `${value.toFixed(2).replace('.', ',')}%`;
}

function summaryText(activeCount: number, greenPercentage: number, attentionPercentage: number) {
  if (activeCount === 0) {
    return 'Sem revisoes avaliaveis';
  }

  return `Verde ${formatPercentage(greenPercentage)} | Atencao ${formatPercentage(attentionPercentage)}`;
}

function formatPerformance(rate: number) {
  return `${Math.round(rate * 100)}%`;
}

function formatLastReviewed(value?: string | null) {
  if (!value) {
    return 'Nunca revisado';
  }

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return 'Data invalida';
  }

  return date.toLocaleDateString('pt-BR');
}

function orderCardsForSession(cards: FlashcardCard[], ragByLibraryId: Map<number, FlashcardRagLibrary>) {
  const buckets: FlashcardCard[][] = [[], [], [], []];

  cards.forEach((card) => {
    const ragLibrary = ragByLibraryId.get(card.libraryId);
    const status = ragLibrary?.ragStatus || 'Grey';
    buckets[STATUS_PRIORITY[status]].push(card);
  });

  return buckets.flatMap((bucket) => shuffleCards(bucket));
}

export function SpacedReviewComponent() {
  const [dashboard, setDashboard] = useState<FlashcardRagDashboardResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedStatuses, setSelectedStatuses] = useState<FlashcardRagStatus[]>(['Red', 'Amber', 'Green', 'Grey']);
  const [selectedLibraryIds, setSelectedLibraryIds] = useState<number[]>([]);
  const [selectedSubjects, setSelectedSubjects] = useState<string[]>([]);
  const [selectedSubSubjects, setSelectedSubSubjects] = useState<string[]>([]);
  const [startingSession, setStartingSession] = useState(false);
  const [sessionCards, setSessionCards] = useState<FlashcardCard[]>([]);
  const [sessionLibraries, setSessionLibraries] = useState<FlashcardRagLibrary[]>([]);
  const [currentIndex, setCurrentIndex] = useState(0);
  const [showAnswer, setShowAnswer] = useState(false);
  const [submittingAnswer, setSubmittingAnswer] = useState(false);

  const loadDashboard = async (preserveSelection: boolean) => {
    setLoading(true);
    setError(null);

    try {
      const response = await MindforgeApiService.getFlashcardRagStatus();
      setDashboard(response);

      const allLibraryIds = response.subjects.flatMap((subjectGroup) =>
        subjectGroup.subSubjects.flatMap((subSubjectGroup) =>
          subSubjectGroup.libraries.map((library) => library.libraryId)),
      );

      setSelectedLibraryIds((current) => {
        if (!preserveSelection || current.length === 0) {
          return allLibraryIds;
        }

        const available = new Set(allLibraryIds);
        const kept = current.filter((libraryId) => available.has(libraryId));
        return kept.length > 0 ? kept : allLibraryIds;
      });

      setSelectedStatuses((current) => {
        if (current.length > 0) {
          return current;
        }

        return ['Red', 'Amber', 'Green', 'Grey'];
      });
    } catch (err: any) {
      setError(err?.message || 'Falha ao carregar status de revisao espacada.');
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    let cancelled = false;

    async function runLoad() {
      if (cancelled) {
        return;
      }

      await loadDashboard(false);
    }

    runLoad();
    return () => {
      cancelled = true;
    };
  }, []);

  const startSession = async () => {
    if (selectedStatuses.length === 0) {
      setError('Selecione ao menos um status para iniciar a revisao.');
      return;
    }

    if (selectedLibraryIds.length === 0) {
      setError('Selecione ao menos um arquivo para iniciar a revisao.');
      return;
    }

    if (selectedRagLibraries.length === 0) {
      setError('Nenhum arquivo encontrado com os filtros atuais. Ajuste os status ou os arquivos selecionados.');
      return;
    }

    setStartingSession(true);
    setError(null);

    try {
      const ragByLibraryId = new Map(selectedRagLibraries.map((library) => [library.libraryId, library]));
      const libraryIds = Array.from(new Set(selectedRagLibraries.map((library) => library.libraryId)));
      const response = await MindforgeApiService.createFlashcardReviewSession({ libraryIds });
      const allowedLibraryIds = new Set(libraryIds);
      const filteredCards = response.cards.filter((card) => allowedLibraryIds.has(card.libraryId));
      const orderedCards = orderCardsForSession(filteredCards, ragByLibraryId);

      if (orderedCards.length === 0) {
        setError('Os filtros selecionados nao retornaram cards para revisar.');
        return;
      }

      setSessionLibraries(selectedRagLibraries);
      setSessionCards(orderedCards);
      setCurrentIndex(0);
      setShowAnswer(false);
    } catch (err: any) {
      setError(err?.message || 'Falha ao iniciar revisao espacada.');
    } finally {
      setStartingSession(false);
    }
  };

  const allRagLibraries = useMemo(() => {
    if (!dashboard) {
      return [];
    }

    return dashboard.subjects.flatMap((subjectGroup) =>
      subjectGroup.subSubjects.flatMap((subSubjectGroup) => subSubjectGroup.libraries));
  }, [dashboard]);

  const selectedRagLibraries = useMemo(() => {
    const statusSet = new Set(selectedStatuses);
    const libraryIdSet = new Set(selectedLibraryIds);

    return allRagLibraries.filter((library) =>
      libraryIdSet.has(library.libraryId) && statusSet.has(library.ragStatus));
  }, [allRagLibraries, selectedLibraryIds, selectedStatuses]);

  const sessionLibraryById = useMemo(() => {
    return new Map(sessionLibraries.map((library) => [library.libraryId, library]));
  }, [sessionLibraries]);

  const currentCard = sessionCards[currentIndex];
  const currentLibrary = currentCard ? sessionLibraryById.get(currentCard.libraryId) : undefined;
  const currentStatusMeta = currentLibrary
    ? STATUS_META_BY_STATUS[currentLibrary.ragStatus]
    : STATUS_META_BY_STATUS.Grey;

  const progressPercent = sessionCards.length > 0
    ? ((currentIndex + 1) / sessionCards.length) * 100
    : 0;

  const toggleStatus = (status: FlashcardRagStatus) => {
    if (selectedStatuses.includes(status)) {
      setSelectedStatuses(selectedStatuses.filter((value) => value !== status));
      return;
    }

    setSelectedStatuses([...selectedStatuses, status]);
  };

  const toggleLibrary = (libraryId: number) => {
    if (selectedLibraryIds.includes(libraryId)) {
      setSelectedLibraryIds(selectedLibraryIds.filter((id) => id !== libraryId));
      return;
    }

    setSelectedLibraryIds([...selectedLibraryIds, libraryId]);
  };

  const toggleSubject = (subject: string) => {
    if (selectedSubjects.includes(subject)) {
      setSelectedSubjects(selectedSubjects.filter((s) => s !== subject));
      const subjectGroup = dashboard?.subjects.find((s) => s.subject === subject);
      if (subjectGroup) {
        const libraryIdsToRemove = subjectGroup.subSubjects.flatMap((ss) =>
          ss.libraries.map((lib) => lib.libraryId));
        setSelectedLibraryIds((current) => current.filter((id) => !libraryIdsToRemove.includes(id)));
        const subSubjectKeysToRemove = subjectGroup.subSubjects.map((ss) => `${subject}::${ss.subSubject}`);
        setSelectedSubSubjects((current) => current.filter((key) => !subSubjectKeysToRemove.includes(key)));
      }
      return;
    }

    setSelectedSubjects([...selectedSubjects, subject]);
    const subjectGroup = dashboard?.subjects.find((s) => s.subject === subject);
    if (subjectGroup) {
      const libraryIdsToAdd = subjectGroup.subSubjects.flatMap((ss) =>
        ss.libraries.map((lib) => lib.libraryId));
      setSelectedLibraryIds((current) => [...new Set([...current, ...libraryIdsToAdd])]);
      const subSubjectKeysToAdd = subjectGroup.subSubjects.map((ss) => `${subject}::${ss.subSubject}`);
      setSelectedSubSubjects((current) => [...new Set([...current, ...subSubjectKeysToAdd])]);
    }
  };

  const toggleSubSubject = (subject: string, subSubject: string) => {
    const key = `${subject}::${subSubject}`;
    if (selectedSubSubjects.includes(key)) {
      setSelectedSubSubjects(selectedSubSubjects.filter((k) => k !== key));
      const subjectGroup = dashboard?.subjects.find((s) => s.subject === subject);
      const subSubjectGroup = subjectGroup?.subSubjects.find((ss) => ss.subSubject === subSubject);
      if (subSubjectGroup) {
        const libraryIdsToRemove = subSubjectGroup.libraries.map((lib) => lib.libraryId);
        setSelectedLibraryIds((current) => current.filter((id) => !libraryIdsToRemove.includes(id)));
      }
      const parentSubjectStillSelected = selectedSubSubjects.some((k) =>
        k.startsWith(`${subject}::`) && k !== key);
      if (!parentSubjectStillSelected) {
        setSelectedSubjects((current) => current.filter((s) => s !== subject));
      }
      return;
    }

    setSelectedSubSubjects([...selectedSubSubjects, key]);
    const subjectGroup = dashboard?.subjects.find((s) => s.subject === subject);
    const subSubjectGroup = subjectGroup?.subSubjects.find((ss) => ss.subSubject === subSubject);
    if (subSubjectGroup) {
      const libraryIdsToAdd = subSubjectGroup.libraries.map((lib) => lib.libraryId);
      setSelectedLibraryIds((current) => [...new Set([...current, ...libraryIdsToAdd])]);
    }
    const allSubSubjects = subjectGroup?.subSubjects.map((ss) => `${subject}::${ss.subSubject}`) || [];
    const allSelected = allSubSubjects.every((k) =>
      k === key || selectedSubSubjects.includes(k));
    if (allSelected && subject && !selectedSubjects.includes(subject)) {
      setSelectedSubjects((current) => [...current, subject]);
    }
  };

  const startSession = async () => {
    if (selectedStatuses.length === 0) {
      setError('Selecione ao menos um status para iniciar a revisao.');
      return;
    }

    if (selectedLibraryIds.length === 0) {
      setError('Selecione ao menos um arquivo para iniciar a revisao.');
      return;
    }

    if (selectedRagLibraries.length === 0) {
      setError('Nenhum arquivo encontrado com os filtros atuais. Ajuste os status ou os arquivos selecionados.');
      return;
    }

    setStartingSession(true);
    setError(null);

    try {
      const ragByLibraryId = new Map(selectedRagLibraries.map((library) => [library.libraryId, library]));
      const libraryIds = Array.from(new Set(selectedRagLibraries.map((library) => library.libraryId)));
      const response = await MindforgeApiService.createFlashcardReviewSession({ libraryIds });
      const allowedLibraryIds = new Set(libraryIds);
      const filteredCards = response.cards.filter((card) => allowedLibraryIds.has(card.libraryId));
      const orderedCards = orderCardsForSession(filteredCards, ragByLibraryId);

      if (orderedCards.length === 0) {
        setError('Os filtros selecionados nao retornaram cards para revisar.');
        return;
      }

      setSessionLibraries(selectedRagLibraries);
      setSessionCards(orderedCards);
      setCurrentIndex(0);
      setShowAnswer(false);
    } catch (err: any) {
      setError(err?.message || 'Falha ao iniciar revisao espacada.');
    } finally {
      setStartingSession(false);
    }
  };

  const endSession = () => {
    setSessionCards([]);
    setSessionLibraries([]);
    setCurrentIndex(0);
    setShowAnswer(false);
    setSubmittingAnswer(false);
    void loadDashboard(true);
  };

  const goToPrevious = () => {
    if (currentIndex === 0) {
      return;
    }

    setCurrentIndex(currentIndex - 1);
    setShowAnswer(false);
  };

  const registerAnswer = async (correct: boolean) => {
    if (!currentCard) {
      return;
    }

    setSubmittingAnswer(true);
    setError(null);

    try {
      await MindforgeApiService.recordFlashcardReviewAnswer({
        cardId: currentCard.id,
        correct,
      });

      if (currentIndex >= sessionCards.length - 1) {
        endSession();
        return;
      }

      setCurrentIndex(currentIndex + 1);
      setShowAnswer(false);
    } catch (err: any) {
      setError(err?.message || 'Falha ao registrar resposta da revisao.');
    } finally {
      setSubmittingAnswer(false);
    }
  };

  return (
    <div className="spaced-review-container">
      <h2 className="title spaced-review-title">Revisao espacada</h2>
      <p className="subtitle">Acompanhe o status RAG por arquivo de flashcards.</p>

      {error && <div className="spaced-review-error">{error}</div>}

      {sessionCards.length === 0 && (
        <div className="spaced-review-panel">
          {loading && <p className="spaced-review-state">Carregando painel de revisao...</p>}
          {!loading && (!dashboard || dashboard.subjects.length === 0) && (
            <p className="spaced-review-state">Nenhum flashcard encontrado para revisar.</p>
          )}

          {!loading && dashboard && dashboard.subjects.length > 0 && (
            <>
              <div className="spaced-review-filters">
                {STATUS_OPTIONS.map((option) => (
                  <label key={option.status} className={`spaced-review-filter ${STATUS_META_BY_STATUS[option.status].className}`}>
                    <input
                      type="checkbox"
                      checked={selectedStatuses.includes(option.status)}
                      onChange={() => toggleStatus(option.status)}
                    />
                    <span className="rag-badge-inline">
                      <span className="rag-icon">{option.icon}</span>
                      {option.label}
                    </span>
                  </label>
                ))}
              </div>

              <div className="spaced-review-subjects">
                {dashboard.subjects.map((subjectGroup) => (
                  <section key={subjectGroup.subject} className="spaced-review-subject">
                    <header className="spaced-review-subject-header">
                      <label className="spaced-review-subject-toggle">
                        <input
                          type="checkbox"
                          checked={selectedSubjects.includes(subjectGroup.subject)}
                          onChange={() => toggleSubject(subjectGroup.subject)}
                        />
                        <h3>{subjectGroup.subject}</h3>
                      </label>
                      <p>{summaryText(
                        subjectGroup.summary.activeCount,
                        subjectGroup.summary.greenPercentage,
                        subjectGroup.summary.attentionPercentage,
                      )}</p>
                      <small>
                        Verde: {subjectGroup.summary.greenCount} | Amarelo: {subjectGroup.summary.amberCount}
                        {' '}
                        | Vermelho: {subjectGroup.summary.redCount} | Cinza: {subjectGroup.summary.greyCount}
                      </small>
                    </header>

                    <div className="spaced-review-subsubject-list">
                      {subjectGroup.subSubjects.map((subSubjectGroup) => (
                        <div key={`${subjectGroup.subject}::${subSubjectGroup.subSubject}`} className="spaced-review-subsubject-block">
                          <div className="spaced-review-subsubject-header">
                            <label className="spaced-review-subsubject-toggle">
                              <input
                                type="checkbox"
                                checked={selectedSubSubjects.includes(`${subjectGroup.subject}::${subSubjectGroup.subSubject}`)}
                                onChange={() => toggleSubSubject(subjectGroup.subject, subSubjectGroup.subSubject)}
                              />
                              <strong>{subSubjectGroup.subSubject}</strong>
                            </label>
                            <span>{summaryText(
                              subSubjectGroup.summary.activeCount,
                              subSubjectGroup.summary.greenPercentage,
                              subSubjectGroup.summary.attentionPercentage,
                            )}</span>
                            <small>
                              Arquivos: {subSubjectGroup.libraries.length} | Cinza: {subSubjectGroup.summary.greyCount}
                            </small>
                          </div>

                          <div className="spaced-review-library-list">
                            {subSubjectGroup.libraries.map((library) => {
                              const statusMeta = STATUS_META_BY_STATUS[library.ragStatus];
                              const selected = selectedLibraryIds.includes(library.libraryId);

                              return (
                                <label
                                  key={library.libraryId}
                                  className={`spaced-review-library-item ${statusMeta.className} ${selected ? 'selected' : ''}`}
                                >
                                  <input
                                    type="checkbox"
                                    checked={selected}
                                    onChange={() => toggleLibrary(library.libraryId)}
                                  />
                                  <div className="spaced-review-library-texts">
                                    <strong>{library.fileName}</strong>
                                    <span>
                                      Cards: {library.cardCount} | Desempenho: {formatPerformance(library.performanceRate)}
                                    </span>
                                    <small>Ultima revisao: {formatLastReviewed(library.lastReviewedAt)}</small>
                                  </div>
                                  <span className={`rag-badge ${statusMeta.className}`}>
                                    <span className="rag-icon">{statusMeta.icon}</span>
                                    {statusMeta.label}
                                  </span>
                                </label>
                              );
                            })}
                          </div>
                        </div>
                      ))}
                    </div>
                  </section>
                ))}
              </div>
            </>
          )}

          <div className="spaced-review-footer">
            <p>
              Arquivos selecionados: <strong>{selectedRagLibraries.length}</strong>
            </p>
            <Button
              variant="primary"
              disabled={startingSession || loading}
              onClick={startSession}
            >
              {startingSession ? 'Iniciando...' : 'Iniciar Revisao Espacada'}
            </Button>
          </div>
        </div>
      )}

      {sessionCards.length > 0 && currentCard && (
        <div className="spaced-review-session-panel">
          <div className="spaced-review-progress">
            <span>{currentIndex + 1} / {sessionCards.length}</span>
            <div className="spaced-review-progress-bar">
              <div className="spaced-review-progress-fill" style={{ width: `${progressPercent}%` }} />
            </div>
          </div>

          <article className="spaced-review-card">
            <header>
              <small>
                {currentLibrary?.fileName || 'Arquivo'} - {currentLibrary?.subject || 'Geral'} - {currentLibrary?.subSubject || 'Geral'}
              </small>
              <span className={`rag-badge ${currentStatusMeta.className}`}>
                <span className="rag-icon">{currentStatusMeta.icon}</span>
                {currentStatusMeta.label}
              </span>
            </header>

            <h3>Frente</h3>
            <p>{currentCard.front}</p>

            {showAnswer && (
              <>
                <h3>Verso</h3>
                <p>{currentCard.back}</p>
                <div className="spaced-review-card-meta">
                  <span>Desempenho do arquivo: {currentLibrary ? formatPerformance(currentLibrary.performanceRate) : '-'}</span>
                  <span>Ultima revisao: {formatLastReviewed(currentLibrary?.lastReviewedAt)}</span>
                </div>
              </>
            )}
          </article>

          <div className="spaced-review-session-actions">
            <Button variant="secondary" onClick={goToPrevious} disabled={currentIndex === 0 || submittingAnswer}>
              Anterior
            </Button>

            {!showAnswer && (
              <Button variant="primary" onClick={() => setShowAnswer(true)}>
                Revelar Resposta
              </Button>
            )}

            {showAnswer && (
              <>
                <Button variant="primary" onClick={() => registerAnswer(true)} disabled={submittingAnswer}>
                  Acertei
                </Button>
                <Button variant="secondary" onClick={() => registerAnswer(false)} disabled={submittingAnswer}>
                  Errei
                </Button>
              </>
            )}

            <Button variant="secondary" onClick={endSession}>
              Encerrar Sessao
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}
