import fs from 'fs';
import path from 'path';
import { prisma } from '../config/database';
import { profileRepository } from '../repositories/profileRepository';
import { documentRepository } from '../repositories/documentRepository';
import { activityRepository } from '../repositories/activityRepository';
import { AppError, toISO } from '../utils/helpers';
import { DocumentType, Jurusan, RegStatus, SenderType } from '@prisma/client';
import { env } from '../config/env';

const ALLOWED_DOC_TYPES: DocumentType[] = [
  'ktp',
  'ijazah',
  'kk',
  'foto',
  'sehat',
  'skl',
  'raport',
];

export const studentService = {
  async getProfile(userId: number) {
    const profile = await profileRepository.findByUserId(userId);
    if (!profile) {
      throw new AppError('Profile not found', 404);
    }
    return { ...profile, tanggalLahir: toISO(profile.tanggalLahir) };
  },

  async updateProfile(
    userId: number,
    data: {
      fullName?: string;
      phoneNumber?: string | null;
      address?: string | null;
      asalSekolah?: string | null;
      jurusan?: Jurusan | null;
      angkatan?: number | null;
      tempatLahir?: string | null;
      tanggalLahir?: string | null;
      jenisKelamin?: string | null;
    }
  ) {
    const updated = await profileRepository.upsert(userId, {
      fullName: data.fullName,
      phoneNumber: data.phoneNumber,
      address: data.address,
      asalSekolah: data.asalSekolah,
      jurusan: data.jurusan,
      angkatan: data.angkatan,
      tempatLahir: data.tempatLahir,
      tanggalLahir: data.tanggalLahir ? new Date(data.tanggalLahir) : null,
      jenisKelamin: data.jenisKelamin,
    });

    await activityRepository.log({
      userId,
      description: 'Student updated profile',
      status: 'update',
    });
    return { ...updated, tanggalLahir: toISO(updated.tanggalLahir) };
  },

  async getEducation(userId: number) {
    return prisma.educationHistory.findMany({
      where: { userId },
      orderBy: { id: 'asc' },
    });
  },

  async updateEducation(
    userId: number,
    entries: Array<{
      jenjang?: string;
      namaSekolah?: string;
      tahunLulus?: number | string;
      nilaiUjian?: number;
    }>
  ) {
    await prisma.educationHistory.deleteMany({ where: { userId } });
    const created = await prisma.educationHistory.createMany({
      data: entries.map((e) => ({
        userId,
        jenjang: e.jenjang ?? null,
        namaSekolah: e.namaSekolah ?? null,
        tahunLulus:
          typeof e.tahunLulus === 'string'
            ? parseInt(e.tahunLulus, 10) || null
            : (e.tahunLulus ?? null),
        nilaiUjian: e.nilaiUjian ?? null,
      })),
    });

    await prisma.registrationStatus.updateMany({
      where: { userId },
      data: { lastStepCompleted: 2 },
    });

    await activityRepository.log({
      userId,
      description: 'Student updated education history',
      status: 'update',
    });
    return prisma.educationHistory.findMany({ where: { userId } });
  },

  async uploadDocument(
    userId: number,
    file: Express.Multer.File,
    documentType: string
  ) {
    if (!ALLOWED_DOC_TYPES.includes(documentType as DocumentType)) {
      throw new AppError('Invalid document type', 400);
    }
    const doc = await documentRepository.upsert(
      userId,
      documentType as DocumentType,
      {
        originalName: file.originalname,
        filePath: file.filename,
        fileSize: file.size,
        mimeType: file.mimetype,
      }
    );

    await activityRepository.log({
      userId,
      description: `Uploaded document: ${documentType}`,
      status: 'upload',
    });
    return doc;
  },

  async getDocuments(userId: number) {
    return documentRepository.findByUser(userId);
  },

  async submitApplication(userId: number) {
    const reg = await prisma.registrationStatus.upsert({
      where: { userId },
      update: { status: 'submitted' as RegStatus },
      create: { userId, status: 'submitted' as RegStatus },
    });
    await profileRepository.updateStatusPendaftaran(userId, 'processing');

    await activityRepository.log({
      userId,
      description: 'Application submitted',
      status: 'submit',
    });
    return reg;
  },

  async getPayments(userId: number) {
    const payments = await prisma.payment.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
    });
    return payments.map((p) => ({ ...p, paidAt: toISO(p.paidAt) }));
  },

  async getNotifications(userId: number) {
    const notifications = await prisma.notification.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
    });
    return notifications.map((n) => ({ ...n, createdAt: toISO(n.createdAt) }));
  },

  async markNotificationsRead(userId: number) {
    await prisma.notification.updateMany({
      where: { userId, isRead: false },
      data: { isRead: true },
    });
    return { success: true };
  },

  async sendMessage(userId: number, message: string) {
    if (message === '__load__') {
      const history = await prisma.message.findMany({
        where: { userId },
        orderBy: { createdAt: 'asc' },
      });
      return { history: history.map((m) => ({ ...m, createdAt: toISO(m.createdAt) })) };
    }

    const saved = await prisma.message.create({
      data: {
        userId,
        senderType: 'student' as SenderType,
        message,
      },
    });
    return { message: { ...saved, createdAt: toISO(saved.createdAt) } };
  },
};
