import db from '@/db/models';
import { withTransaction } from '@/db/with-transaction';
import { resolvePagination } from '@/shared/constants/pagination';
import ValidationError from '@/shared/errors/validation';
import {
  getOrganizationIdOrGlobal,
  getCampusId,
  assertAuthenticatedTenantUser,
  hasRoleAccess,
  getDisplayName,
} from '@/services/shared/access';
import { ROLE_NAMES } from '@/shared/constants/roles';
import { SAFETY_QUIZ_REPORT_ROLE_NAMES } from '@/shared/constants/safety-quiz';
import type { SafetyQuizResults } from '@/db/models/safety_quiz_results';
import type { CurrentUser } from '@/db/api/types';

interface SafetyQuizInput {
  quiz_id: string;
  quiz_title: string;
  week_of: string;
  score: number;
  total_questions: number;
  answers: unknown;
}

interface SafetyQuizFilter {
  week_of?: string;
  limit?: number | string;
  page?: number | string;
}

const REQUIRED_STRINGS = ['quiz_id', 'quiz_title', 'week_of'] as const;

function getProductRole(currentUser?: CurrentUser): string {
  return currentUser?.app_role?.name ?? ROLE_NAMES.TEACHER;
}

function assertValidResult(data: SafetyQuizInput): void {
  if (!data || typeof data !== 'object' || Array.isArray(data)) {
    throw new ValidationError();
  }

  const hasMissingString = REQUIRED_STRINGS.some((field) => {
    const value = data[field];
    return typeof value !== 'string' || value.trim().length === 0;
  });

  if (
    hasMissingString ||
    !Number.isInteger(data.score) ||
    !Number.isInteger(data.total_questions) ||
    !Array.isArray(data.answers) ||
    !data.answers.every((value) => Number.isInteger(value))
  ) {
    throw new ValidationError();
  }
}

function toDto(record: SafetyQuizResults) {
  const plain = record.get({ plain: true });

  return {
    id: plain.id,
    quiz_id: plain.quiz_id,
    quiz_title: plain.quiz_title,
    week_of: plain.week_of,
    score: plain.score,
    total_questions: plain.total_questions,
    answers: plain.answers,
    user_name: plain.user_name,
    user_role: plain.user_role,
    completed_at: plain.completed_at,
    organizationId: plain.organizationId,
    campusId: plain.campusId,
    userId: plain.userId,
    createdAt: plain.createdAt,
    updatedAt: plain.updatedAt,
  };
}

class SafetyQuizResultsService {
  static async list(filter: SafetyQuizFilter, currentUser?: CurrentUser) {
    assertAuthenticatedTenantUser(currentUser);
    const { limit, offset } = resolvePagination(filter.limit, filter.page);

    const organizationId = getOrganizationIdOrGlobal(currentUser);
    const orgFilter = organizationId ? { organizationId } : {};

    const result = await db.safety_quiz_results.findAndCountAll({
      where: {
        ...orgFilter,
        ...(hasRoleAccess(currentUser, SAFETY_QUIZ_REPORT_ROLE_NAMES)
          ? {}
          : { userId: currentUser?.id ?? null }),
        ...(filter.week_of ? { week_of: filter.week_of } : {}),
      },
      order: [['completed_at', 'desc']],
      limit,
      offset,
    });

    return {
      rows: result.rows.map(toDto),
      count: result.count,
    };
  }

  static async create(data: SafetyQuizInput, currentUser?: CurrentUser) {
    assertAuthenticatedTenantUser(currentUser);
    assertValidResult(data);

    const organizationId = getOrganizationIdOrGlobal(currentUser);

    return withTransaction(async (transaction) => {
      const created = await db.safety_quiz_results.create(
        {
          quiz_id: data.quiz_id.trim(),
          quiz_title: data.quiz_title.trim(),
          week_of: data.week_of.trim(),
          score: data.score,
          total_questions: data.total_questions,
          answers: data.answers,
          user_name: getDisplayName(currentUser),
          user_role: getProductRole(currentUser),
          completed_at: new Date(),
          organizationId,
          campusId: getCampusId(currentUser),
          userId: currentUser?.id ?? null,
          createdById: currentUser?.id ?? null,
          updatedById: currentUser?.id ?? null,
        },
        { transaction },
      );

      return toDto(created);
    });
  }
}

export default SafetyQuizResultsService;
