import {
  LevelCode,
  Prisma,
  PrismaClient,
  QuestionContentType,
  QuestionType,
  SkillType,
  UserRole,
} from '@prisma/client';
import { hashPassword } from '../src/common/utils/password.util';

const prisma = new PrismaClient();

const DEMO_COURSE_CODE = 'DEMO-A1';
const DEMO_QUESTIONS_PER_SKILL = 8;

const DEMO_SKILL_CONFIG: Array<{
  skill: SkillType;
  slug: string;
  areaName: string;
  sectionName: string;
}> = [
  {
    skill: SkillType.READING,
    slug: 'READING',
    areaName: 'Reading',
    sectionName: 'Demo reading',
  },
  {
    skill: SkillType.LISTENING,
    slug: 'LISTENING',
    areaName: 'Listening',
    sectionName: 'Demo listening',
  },
  {
    skill: SkillType.GRAMMAR,
    slug: 'GRAMMAR',
    areaName: 'Grammar',
    sectionName: 'Demo grammar',
  },
  {
    skill: SkillType.VOCABULARY,
    slug: 'VOCABULARY',
    areaName: 'Vocabulary',
    sectionName: 'Demo vocabulary',
  },
];

export async function main(): Promise<void> {
  const email = process.env.SEED_ADMIN_EMAIL ?? 'admin@testingles.local';
  const password = process.env.SEED_ADMIN_PASSWORD ?? 'admin1234';
  const firstName = process.env.SEED_ADMIN_FIRST_NAME ?? 'System';
  const lastName = process.env.SEED_ADMIN_LAST_NAME ?? 'Admin';
  const demoStudentEmail =
    process.env.SEED_DEMO_STUDENT_EMAIL ?? 'alumno.demo@testingles.local';
  const demoStudentPassword =
    process.env.SEED_DEMO_STUDENT_PASSWORD ?? 'Demo1234';
  const demoStudentFirstName =
    process.env.SEED_DEMO_STUDENT_FIRST_NAME ?? 'Alumno';
  const demoStudentLastName =
    process.env.SEED_DEMO_STUDENT_LAST_NAME ?? 'Demo';
  const demoStudentRut =
    process.env.SEED_DEMO_STUDENT_RUT ?? '12.345.678-5';
  const demoStudentMoodleId =
    process.env.SEED_DEMO_STUDENT_MOODLE_ID ?? 'moodle-demo-student';
  const demoStudentCourseName =
    process.env.SEED_DEMO_STUDENT_COURSE_NAME ?? 'Curso Demo A1';

  const passwordHash = await hashPassword(password);
  const demoStudentPasswordHash = await hashPassword(demoStudentPassword);

  await prisma.user.upsert({
    where: { email },
    update: {
      passwordHash,
      firstName,
      lastName,
      role: UserRole.ADMIN,
      isActive: true,
    },
    create: {
      email,
      passwordHash,
      firstName,
      lastName,
      role: UserRole.ADMIN,
      isActive: true,
    },
  });

  await prisma.course.upsert({
    where: {
      code: DEMO_COURSE_CODE,
    },
    update: {
      name: 'Demo English Placement Course A1',
      description:
        'Seeded demo course used to validate the Angular + NestJS migration flow.',
      levelCode: LevelCode.A1,
      isActive: true,
    },
    create: {
      code: DEMO_COURSE_CODE,
      name: 'Demo English Placement Course A1',
      description:
        'Seeded demo course used to validate the Angular + NestJS migration flow.',
      levelCode: LevelCode.A1,
      isActive: true,
    },
  });

  await seedAdminCatalogs();

  const demoUser = await prisma.user.upsert({
    where: {
      email: demoStudentEmail,
    },
    update: {
      passwordHash: demoStudentPasswordHash,
      firstName: demoStudentFirstName,
      lastName: demoStudentLastName,
      role: UserRole.STUDENT,
      isActive: true,
    },
    create: {
      email: demoStudentEmail,
      passwordHash: demoStudentPasswordHash,
      firstName: demoStudentFirstName,
      lastName: demoStudentLastName,
      role: UserRole.STUDENT,
      isActive: true,
    },
  });

  const demoFullName =
    `${demoStudentFirstName} ${demoStudentLastName}`.trim() ||
    'Alumno Demo';

  await prisma.student.upsert({
    where: {
      moodleUserId: demoStudentMoodleId,
    },
    update: {
      userId: demoUser.id,
      email: demoStudentEmail,
      firstName: demoStudentFirstName,
      lastName: demoStudentLastName,
      fullName: demoFullName,
      moodleUserId: demoStudentMoodleId,
      rut: demoStudentRut,
      courseName: demoStudentCourseName,
      codEnse: '110',
      codGrado: '7',
      establishmentName: 'Demo High School',
      commune: 'Santiago',
      province: 'Santiago',
      region: 'Metropolitana',
      isActive: true,
    },
    create: {
      userId: demoUser.id,
      email: demoStudentEmail,
      firstName: demoStudentFirstName,
      lastName: demoStudentLastName,
      fullName: demoFullName,
      moodleUserId: demoStudentMoodleId,
      rut: demoStudentRut,
      courseName: demoStudentCourseName,
      codEnse: '110',
      codGrado: '7',
      establishmentName: 'Demo High School',
      commune: 'Santiago',
      province: 'Santiago',
      region: 'Metropolitana',
      isActive: true,
    },
  });

  await seedDemoQuestionBank();
}

async function seedAdminCatalogs(): Promise<void> {
  const testTypes = [
    {
      code: 'PLACEMENT',
      name: 'Placement Test / Test de nivelacion',
      description:
        'Determina el nivel actual de ingles del estudiante mediante reglas configurables.',
      purpose: 'Asignar nivel global y orientar recomendaciones generales.',
      allowsComparison: true,
      allowsRecommendations: true,
      allowsStandaloneMode: true,
      allowsMoodleIntegration: true,
      isOfficial: true,
      isPractice: false,
      isActive: true,
    },
    {
      code: 'DIAGNOSTIC',
      name: 'Diagnostic Test / Test diagnostico por habilidad',
      description:
        'Identifica fortalezas, debilidades y brechas por habilidad evaluada.',
      purpose: 'Priorizar refuerzos y recomendaciones por habilidad.',
      allowsComparison: true,
      allowsRecommendations: true,
      allowsStandaloneMode: true,
      allowsMoodleIntegration: true,
      isOfficial: true,
      isPractice: false,
      isActive: true,
    },
    {
      code: 'PRACTICE',
      name: 'Practice Test / Test de practica',
      description:
        'Permite ejercitacion sin afectar resultados oficiales del estudiante.',
      purpose: 'Practicar contenidos y entregar feedback formativo.',
      allowsComparison: false,
      allowsRecommendations: true,
      allowsStandaloneMode: true,
      allowsMoodleIntegration: false,
      isOfficial: false,
      isPractice: true,
      isActive: true,
    },
    {
      code: 'INSTITUTIONAL',
      name: 'Institutional Test / Test institucional configurable',
      description:
        'Evalua objetivos definidos por una institucion con reglas propias.',
      purpose: 'Medir resultados institucionales o cohortes especificas.',
      allowsComparison: true,
      allowsRecommendations: true,
      allowsStandaloneMode: true,
      allowsMoodleIntegration: true,
      isOfficial: true,
      isPractice: false,
      isActive: true,
    },
    {
      code: 'LEGACY',
      name: 'Legacy Test / Test historico compatible',
      description:
        'Reproduce de forma configurable la composicion y nivelacion del sistema historico.',
      purpose:
        'Mantener compatibilidad operativa sin alterar los intentos historicos migrados.',
      allowsComparison: true,
      allowsRecommendations: true,
      allowsStandaloneMode: true,
      allowsMoodleIntegration: false,
      isOfficial: true,
      isPractice: false,
      isActive: true,
    },
  ];

  for (const testType of testTypes) {
    await prisma.testType.upsert({
      where: { code: testType.code },
      update: testType,
      create: testType,
    });
  }

  const languageLevels = [
    ['NONE', 'Sin nivel', null, 'none', 0],
    ['A1_BASIC', 'A1 basico', 'A1', 'basic', 10],
    ['A1_INTERMEDIATE', 'A1 medio', 'A1', 'intermediate', 20],
    ['A1_ADVANCED', 'A1 avanzado', 'A1', 'advanced', 30],
    ['A2_BASIC', 'A2 basico', 'A2', 'basic', 40],
    ['A2_INTERMEDIATE', 'A2 medio', 'A2', 'intermediate', 50],
    ['A2_ADVANCED', 'A2 avanzado', 'A2', 'advanced', 60],
    ['B1_BASIC', 'B1 basico', 'B1', 'basic', 70],
    ['B1_INTERMEDIATE', 'B1 medio', 'B1', 'intermediate', 80],
    ['B1_ADVANCED', 'B1 avanzado', 'B1', 'advanced', 90],
  ] as const;

  for (const [code, name, cefrLevel, difficultyBand, sortOrder] of languageLevels) {
    await prisma.languageLevel.upsert({
      where: { code },
      update: {
        name,
        cefrLevel,
        difficultyBand,
        sortOrder,
        isActive: true,
      },
      create: {
        code,
        name,
        cefrLevel,
        difficultyBand,
        sortOrder,
        isActive: true,
      },
    });
  }
}

async function seedDemoQuestionBank(): Promise<void> {
  const activeLegacyQuestions = await prisma.question.count({
    where: {
      legacyQuestionId: {
        not: null,
      },
      isActive: true,
    },
  });
  const shouldActivateDemoQuestions = activeLegacyQuestions === 0;

  for (const skillConfig of DEMO_SKILL_CONFIG) {
    for (let index = 1; index <= DEMO_QUESTIONS_PER_SKILL; index += 1) {
      const code = `DEMO-A1-${skillConfig.slug}-${index.toString().padStart(2, '0')}`;
      const existingQuestion = await prisma.question.findUnique({
        where: {
          code,
        },
        select: {
          id: true,
        },
      });

      if (existingQuestion) {
        await prisma.question.update({
          where: {
            id: existingQuestion.id,
          },
          data: {
            skill: skillConfig.skill,
            levelCode: LevelCode.A1,
            type: QuestionType.SINGLE_CHOICE,
            contentType: QuestionContentType.TEXT,
            areaName: skillConfig.areaName,
            sectionName: skillConfig.sectionName,
            prompt: buildDemoPrompt(skillConfig.areaName, index),
            title: `${skillConfig.areaName} demo question ${index}`,
            points: new Prisma.Decimal(1),
            shuffleOptions: false,
            isActive: shouldActivateDemoQuestions,
          },
        });

        continue;
      }

      await prisma.question.create({
        data: {
          code,
          skill: skillConfig.skill,
          levelCode: LevelCode.A1,
          type: QuestionType.SINGLE_CHOICE,
          contentType: QuestionContentType.TEXT,
          areaName: skillConfig.areaName,
          sectionName: skillConfig.sectionName,
          prompt: buildDemoPrompt(skillConfig.areaName, index),
          title: `${skillConfig.areaName} demo question ${index}`,
          points: new Prisma.Decimal(1),
          shuffleOptions: false,
          isActive: shouldActivateDemoQuestions,
          options: {
            create: [
              {
                text: `Correct option for ${skillConfig.areaName} ${index}`,
                isCorrect: true,
                sortOrder: 1,
                isActive: true,
              },
              {
                text: `Distractor option for ${skillConfig.areaName} ${index}`,
                isCorrect: false,
                sortOrder: 2,
                isActive: true,
              },
            ],
          },
        },
      });
    }
  }
}

function buildDemoPrompt(areaName: string, index: number): string {
  return `Demo ${areaName.toLowerCase()} prompt ${index}. Select the correct option to keep the migrated flow testable in local environments.`;
}

main()
  .catch((error) => {
    console.error(error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
