import { NextFunction, Request, Response } from 'express';
import { ResultSetHeader, RowDataPacket } from 'mysql2';
import { pool } from '../config/db.js';

interface UnitRow extends RowDataPacket {
  id: number;
  name: string;
}

function mysqlErrorCode(err: unknown): string | undefined {
  return err && typeof err === 'object' && 'code' in err ? (err as { code?: string }).code : undefined;
}

export async function list(_req: Request, res: Response, next: NextFunction) {
  try {
    const [rows] = await pool.query<UnitRow[]>('SELECT id, name FROM units ORDER BY name');
    res.json(rows);
  } catch (err) {
    next(err);
  }
}

export async function create(req: Request, res: Response, next: NextFunction) {
  const { name } = req.body as { name?: string };
  if (!name?.trim()) {
    return res.status(400).json({ message: 'Unit name is required' });
  }

  try {
    const [result] = await pool.query<ResultSetHeader>('INSERT INTO units (name) VALUES (?)', [name.trim()]);
    res.status(201).json({ id: result.insertId, name: name.trim() });
  } catch (err: unknown) {
    if (mysqlErrorCode(err) === 'ER_DUP_ENTRY') {
      return res.status(409).json({ message: 'Unit name already exists' });
    }
    next(err);
  }
}

export async function update(req: Request, res: Response, next: NextFunction) {
  const id = Number(req.params.id);
  const { name } = req.body as { name?: string };
  if (!name?.trim()) {
    return res.status(400).json({ message: 'Unit name is required' });
  }

  try {
    const [result] = await pool.query<ResultSetHeader>('UPDATE units SET name = ? WHERE id = ?', [name.trim(), id]);
    if (result.affectedRows === 0) {
      return res.status(404).json({ message: 'Unit not found' });
    }
    res.json({ id, name: name.trim() });
  } catch (err: unknown) {
    if (mysqlErrorCode(err) === 'ER_DUP_ENTRY') {
      return res.status(409).json({ message: 'Unit name already exists' });
    }
    next(err);
  }
}

export async function remove(req: Request, res: Response, next: NextFunction) {
  const id = Number(req.params.id);
  try {
    const [result] = await pool.query<ResultSetHeader>('DELETE FROM units WHERE id = ?', [id]);
    if (result.affectedRows === 0) {
      return res.status(404).json({ message: 'Unit not found' });
    }
    res.status(204).send();
  } catch (err: unknown) {
    const code = mysqlErrorCode(err);
    if (code === 'ER_ROW_IS_REFERENCED_2' || code === 'ER_ROW_IS_REFERENCED') {
      return res
        .status(409)
        .json({ message: 'This unit has divisions linked to it and cannot be deleted.' });
    }
    next(err);
  }
}
