import { v4 as uuidv4 } from 'uuid';
import { db } from '../application/database';
import { ResponseError } from '../error/response-error';
import { VendorResponse, toVendorResponse, CreateVendorRequest, UpdateVendorRequest, Vendor } from '../model/vendor-model';
import { VendorValidation } from '../validation/vendor-validation';
import { Validation } from '../validation/validation';

export class VendorService {
  static async create(request: CreateVendorRequest): Promise<VendorResponse> {
    // Validate the create request
    const createRequest = Validation.validate(VendorValidation.CREATE, request);

    // Generate a UUID for the new vendor
    const vendorId = uuidv4();

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

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

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

    return toVendorResponse(vendor);
  }

  static async update(id: string, request: UpdateVendorRequest): Promise<VendorResponse> {
    // Validate the update request
    const updateRequest = Validation.validate(VendorValidation.UPDATE, request);

    // Check if the vendor exists
    await this.#checkVendorExist(id);

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

    // Retrieve the updated vendor by the UUID
    const vendor = await db.queryOne<Vendor>('SELECT * FROM vendor WHERE id = ? LIMIT 1', [id]);

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

    return toVendorResponse(vendor);
  }

  static async delete(id: string): Promise<VendorResponse> {
    // Retrieve the vendor before deleting
    const vendor = await db.queryOne<Vendor>('SELECT * FROM vendor WHERE id = ? LIMIT 1', [id]);

    if (!vendor) {
      throw new ResponseError(500, 'Failed to delete vendor');
    }

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

    return toVendorResponse(vendor);
  }

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

    if (!vendor) {
      throw new ResponseError(404, 'Vendor not found');
    }

    return toVendorResponse(vendor);
  }

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

    // Map each vendor to the response format
    return vendors.map(toVendorResponse);
  }

  static async #checkVendorExist(id: string): Promise<void> {
    // Check if the vendor exists
    const vendor = await db.queryOne<{ id: string }>('SELECT id FROM vendor WHERE id = ? LIMIT 1', [id]);

    if (!vendor) {
      throw new ResponseError(404, 'Vendor not found');
    }
  }
}
