import { v4 as uuidv4 } from 'uuid';
import { db } from '../application/database';
import { ResponseError } from '../error/response-error';
import { CategoryResponse, toCategoryResponse, CreateCategoryRequest, Category } from '../model/category-model';
import { CategoryValidation } from '../validation/category-validation';
import { Validation } from '../validation/validation';

export class CategoryService {
  static async create(request: CreateCategoryRequest): Promise<CategoryResponse> {
    // Validate the create request
    const createRequest = Validation.validate(CategoryValidation.CREATE, request);

    // Generate a UUID for the new category
    const categoryId = uuidv4();

    // Insert the new category into the database with the UUID
    await db.query('INSERT INTO category (id, name) VALUES (?, ?)', [categoryId, createRequest.name]);

    // Retrieve the newly created category by the UUID
    const category = await db.queryOne<Category>('SELECT * FROM category WHERE id = ? LIMIT 1', [categoryId]);

    if (!category) {
      throw new ResponseError(500, 'Failed to create category');
    }

    return toCategoryResponse(category);
  }

  static async getAll(): Promise<CategoryResponse[]> {
    // Retrieve all categories from the database
    const categories = await db.query<Category>('SELECT * FROM category ORDER BY created_at ASC');

    // Map each category to the response format
    return categories.map(toCategoryResponse);
  }

  static async get(id: string): Promise<CategoryResponse> {
    // Retrieve a single category by ID
    const category = await db.queryOne<Category>('SELECT * FROM category WHERE id = ? LIMIT 1', [id]);

    if (!category) {
      throw new ResponseError(404, 'Category not found');
    }

    return toCategoryResponse(category);
  }

  static async update(id: string, request: CreateCategoryRequest): Promise<CategoryResponse> {
    // Check if the category exists
    const existingCategory = await db.queryOne<{ id: string }>('SELECT id FROM category WHERE id = ? LIMIT 1', [id]);

    if (!existingCategory) {
      throw new ResponseError(404, 'Category not found');
    }

    // Validate the update request
    const updateRequest = Validation.validate(CategoryValidation.CREATE, request);

    // Update the category in the database
    await db.query('UPDATE category SET name = ? WHERE id = ?', [updateRequest.name, id]);

    // Retrieve the updated category by ID
    const category = await db.queryOne<Category>('SELECT * FROM category WHERE id = ?', [id]);

    if (!category) {
      throw new ResponseError(500, 'Failed to update category');
    }

    return toCategoryResponse(category);
  }

  static async delete(id: string): Promise<CategoryResponse> {
    // Retrieve the category before deleting it
    const category = await db.queryOne<Category>('SELECT * FROM category WHERE id = ?', [id]);

    if (!category) {
      throw new ResponseError(404, 'Category not found');
    }

    // Delete the category from the database
    await db.query('DELETE FROM category WHERE id = ?', [id]);

    return toCategoryResponse(category);
  }
}
