import { initDb } from "@/lib/db";
import type { Candidate } from "@/lib/db/models/candidate";
import type { CandidateQA } from "@/lib/db/models/candidate-qa";
import type { Election } from "@/lib/db/models/election";
import type { CandidateStatus, ElectionPositionType } from "@/types";

export interface CandidateQAView {
  id: string;
  question: string;
  answer: string;
  position: number;
}

export interface CandidateView {
  id: string;
  electionPositionId: string;
  name: string;
  photoUrl: string | null;
  biography: string | null;
  resumeUrl: string | null;
  goalsStatement: string | null;
  conflictOfInterestDisclosure: string | null;
  status: CandidateStatus;
  position: number;
  qas: CandidateQAView[];
}

export interface PositionWithCandidates {
  id: string;
  electionId: string;
  title: string;
  positionType: ElectionPositionType;
  seatsAvailable: number;
  position: number;
  candidates: CandidateView[];
}

function mapCandidate(candidate: Candidate): CandidateView {
  const qas = (candidate.get("qas") as CandidateQA[] | undefined) ?? [];
  return {
    id: candidate.id,
    electionPositionId: candidate.electionPositionId,
    name: candidate.name,
    photoUrl: candidate.photoUrl,
    biography: candidate.biography,
    resumeUrl: candidate.resumeUrl,
    goalsStatement: candidate.goalsStatement,
    conflictOfInterestDisclosure: candidate.conflictOfInterestDisclosure,
    status: candidate.status,
    position: candidate.position,
    qas: qas
      .sort((a, b) => a.position - b.position)
      .map((qa) => ({
        id: qa.id,
        question: qa.question,
        answer: qa.answer,
        position: qa.position,
      })),
  };
}

export async function getElectionPositions(
  electionId: string
): Promise<PositionWithCandidates[]> {
  const { ElectionPosition, Candidate, CandidateQA } = initDb();

  const positions = await ElectionPosition.findAll({
    where: { electionId },
    order: [["position", "ASC"]],
    include: [
      {
        model: Candidate,
        as: "candidates",
        include: [{ model: CandidateQA, as: "qas" }],
      },
    ],
  });

  return positions.map((pos) => {
    const candidates =
      (pos.get("candidates") as Candidate[] | undefined) ?? [];
    return {
      id: pos.id,
      electionId: pos.electionId,
      title: pos.title,
      positionType: pos.positionType,
      seatsAvailable: pos.seatsAvailable,
      position: pos.position,
      candidates: candidates
        .sort((a, b) => a.position - b.position)
        .map(mapCandidate),
    };
  });
}

export async function getPositionForWorkspace(
  electionPositionId: string,
  workspaceId: string
) {
  const { ElectionPosition, Election } = initDb();
  const position = await ElectionPosition.findByPk(electionPositionId, {
    include: [{ model: Election, as: "election" }],
  });
  if (!position) return null;
  const election = position.get("election") as Election | undefined;
  if (!election || election.workspaceId !== workspaceId) return null;
  return { position, election };
}
