import { Request, Response } from 'express';
import { z } from 'zod';
import { adminService } from '../services/adminService';
import { sendSuccess, sendError, asyncHandler, formatZodError } from '../utils/helpers';
import { AuthenticatedRequest } from '../middleware/auth';
import { Role, DocumentType, Jurusan, StatusPendaftaran, RegStatus } from '@prisma/client';

const statusUpdateSchema = z.object({
  statusPendaftaran: z.nativeEnum(StatusPendaftaran).optional(),
  regStatus: z.nativeEnum(RegStatus).optional(),
  adminComment: z.string().optional(),
  nim: z.string().nullable().optional(),
});

const verifySchema = z.object({
  isVerified: z.boolean(),
  adminNote: z.string().optional(),
});

const programSchema = z.object({
  name: z.string().min(1),
  accreditation: z.string().nullable().optional(),
  description: z.string().nullable().optional(),
  quota: z.number().int().min(0),
  isActive: z.boolean().optional(),
});

const announcementSchema = z.object({
  title: z.string().min(1),
  body: z.string().min(1),
  author: z.string().nullable().optional(),
  pinned: z.boolean().optional(),
  published: z.boolean().optional(),
});

const userSchema = z.object({
  email: z.string().email(),
  password: z.string().min(6),
  role: z.nativeEnum(Role),
  nim: z.string().nullable().optional(),
  fullName: z.string().optional(),
  isActive: z.boolean().optional(),
});

export const adminController = {
  dashboardStats: asyncHandler(async (req: Request, res: Response) => {
    const stats = await adminService.dashboardStats();
    return sendSuccess(res, 'Dashboard statistics retrieved', stats, 200);
  }),

  getStudents: asyncHandler(async (req: Request, res: Response) => {
    const result = await adminService.listStudents({
      page: req.query.page ? Number(req.query.page) : 1,
      limit: req.query.limit ? Number(req.query.limit) : 10,
      search: req.query.search as string | undefined,
      status: req.query.status as string | undefined,
      jurusan: req.query.jurusan as string | undefined,
    });
    return sendSuccess(res, 'Students retrieved', result, 200);
  }),

  updateStudentStatus: asyncHandler(async (req: AuthenticatedRequest, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid student id', 400);
    const parsed = statusUpdateSchema.safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const result = await adminService.updateStudentStatus(id, {
      ...parsed.data,
      updatedById: req.user!.userId,
    });
    return sendSuccess(res, 'Student status updated', result, 200);
  }),

  getStudentDocuments: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid student id', 400);
    const docs = await adminService.getStudentDocuments(id);
    return sendSuccess(res, 'Student documents retrieved', docs, 200);
  }),

  getDocuments: asyncHandler(async (req: Request, res: Response) => {
    const result = await adminService.listDocuments({
      page: req.query.page ? Number(req.query.page) : 1,
      limit: req.query.limit ? Number(req.query.limit) : 10,
      isVerified:
        req.query.isVerified === 'true'
          ? true
          : req.query.isVerified === 'false'
          ? false
          : undefined,
      documentType: req.query.documentType as string | undefined,
      userId: req.query.userId ? Number(req.query.userId) : undefined,
    });
    return sendSuccess(res, 'Documents retrieved', result, 200);
  }),

  verifyDocument: asyncHandler(async (req: AuthenticatedRequest, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid document id', 400);
    const parsed = verifySchema.safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const doc = await adminService.verifyDocument(id, {
      ...parsed.data,
      verifiedById: req.user!.userId,
    });
    return sendSuccess(res, 'Document verification updated', doc, 200);
  }),

  // Programs
  getPrograms: asyncHandler(async (req: Request, res: Response) => {
    const programs = await adminService.programs.list(true);
    return sendSuccess(res, 'Programs retrieved', programs, 200);
  }),

  createProgram: asyncHandler(async (req: Request, res: Response) => {
    const parsed = programSchema.safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const program = await adminService.programs.create(parsed.data);
    return sendSuccess(res, 'Program created', program, 201);
  }),

  updateProgram: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid program id', 400);
    const parsed = programSchema.partial().safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const program = await adminService.programs.update(id, parsed.data);
    return sendSuccess(res, 'Program updated', program, 200);
  }),

  deleteProgram: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid program id', 400);
    await adminService.programs.delete(id);
    return sendSuccess(res, 'Program deleted', undefined, 200);
  }),

  // Announcements
  getAnnouncements: asyncHandler(async (req: Request, res: Response) => {
    const publishedOnly = req.query.published === 'true';
    const announcements = await adminService.announcements.list({ publishedOnly });
    return sendSuccess(res, 'Announcements retrieved', announcements, 200);
  }),

  createAnnouncement: asyncHandler(async (req: AuthenticatedRequest, res: Response) => {
    const parsed = announcementSchema.safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const announcement = await adminService.announcements.create({
      ...parsed.data,
      author: parsed.data.author ?? req.user!.email,
    });
    return sendSuccess(res, 'Announcement created', announcement, 201);
  }),

  updateAnnouncement: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid announcement id', 400);
    const parsed = announcementSchema.partial().safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const announcement = await adminService.announcements.update(id, parsed.data);
    return sendSuccess(res, 'Announcement updated', announcement, 200);
  }),

  deleteAnnouncement: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid announcement id', 400);
    await adminService.announcements.delete(id);
    return sendSuccess(res, 'Announcement deleted', undefined, 200);
  }),

  // Users
  getUsers: asyncHandler(async (req: Request, res: Response) => {
    const users = await adminService.listUsers({ search: req.query.search as string });
    return sendSuccess(res, 'Users retrieved', users, 200);
  }),

  createUser: asyncHandler(async (req: Request, res: Response) => {
    const parsed = userSchema.safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const user = await adminService.createUser(parsed.data);
    return sendSuccess(res, 'User created', user, 201);
  }),

  updateUser: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid user id', 400);
    const parsed = userSchema.partial().safeParse(req.body);
    if (!parsed.success) {
      return sendError(res, formatZodError(parsed.error), 400);
    }
    const user = await adminService.updateUser(id, parsed.data);
    return sendSuccess(res, 'User updated', user, 200);
  }),

  deleteUser: asyncHandler(async (req: Request, res: Response) => {
    const id = Number(req.params.id);
    if (isNaN(id)) return sendError(res, 'Invalid user id', 400);
    const result = await adminService.deleteUser(id);
    return sendSuccess(res, 'User deleted', result, 200);
  }),

  // Settings
  getSettings: asyncHandler(async (req: Request, res: Response) => {
    const settings = await adminService.getSettings();
    return sendSuccess(res, 'Settings retrieved', settings, 200);
  }),

  updateSettings: asyncHandler(async (req: Request, res: Response) => {
    const settings = await adminService.updateSettings(req.body);
    return sendSuccess(res, 'Settings updated', settings, 200);
  }),

  // Reports
  getReport: asyncHandler(async (req: Request, res: Response) => {
    const type = req.params.type === 'excel' ? 'excel' : 'pdf';
    const report = await adminService.getReportStudents(type);
    res.setHeader('Content-Type', report.contentType);
    res.setHeader(
      'Content-Disposition',
      `attachment; filename="${report.filename}"`
    );
    return res.send(report.buffer);
  }),
};
