import { query, queryOne } from '../../config/database.js';
import { NotFoundError, ConflictError } from '../../shared/errors/index.js';

export interface UomCategory {
  id: string;
  name: string;
  active: boolean;
}

export interface Uom {
  id: string;
  name: string;
  code: string;
  category_id: string;
  category_name?: string;
  uom_type: 'reference' | 'bigger' | 'smaller';
  ratio: number;
  active: boolean;
}

export interface CreateUomDto {
  name: string;
  code: string;
  category_id: string;
  uom_type?: 'reference' | 'bigger' | 'smaller';
  ratio?: number;
}

export interface UpdateUomDto {
  name?: string;
  ratio?: number;
  active?: boolean;
}

class UomService {
  // Categories
  async findAllCategories(activeOnly: boolean = false): Promise<UomCategory[]> {
    const whereClause = activeOnly ? 'WHERE active = true' : '';
    return query<UomCategory>(
      `SELECT * FROM core.uom_categories ${whereClause} ORDER BY name`
    );
  }

  async findCategoryById(id: string): Promise<UomCategory> {
    const category = await queryOne<UomCategory>(
      `SELECT * FROM core.uom_categories WHERE id = $1`,
      [id]
    );
    if (!category) {
      throw new NotFoundError('Categoría de UdM no encontrada');
    }
    return category;
  }

  // UoM
  async findAll(categoryId?: string, activeOnly: boolean = false): Promise<Uom[]> {
    let whereClause = '';
    const params: any[] = [];
    let paramIndex = 1;

    if (categoryId || activeOnly) {
      const conditions: string[] = [];
      if (categoryId) {
        conditions.push(`u.category_id = $${paramIndex++}`);
        params.push(categoryId);
      }
      if (activeOnly) {
        conditions.push('u.active = true');
      }
      whereClause = 'WHERE ' + conditions.join(' AND ');
    }

    return query<Uom>(
      `SELECT u.*, uc.name as category_name
       FROM core.uom u
       LEFT JOIN core.uom_categories uc ON u.category_id = uc.id
       ${whereClause}
       ORDER BY uc.name, u.uom_type, u.name`,
      params
    );
  }

  async findById(id: string): Promise<Uom> {
    const uom = await queryOne<Uom>(
      `SELECT u.*, uc.name as category_name
       FROM core.uom u
       LEFT JOIN core.uom_categories uc ON u.category_id = uc.id
       WHERE u.id = $1`,
      [id]
    );
    if (!uom) {
      throw new NotFoundError('Unidad de medida no encontrada');
    }
    return uom;
  }

  async create(dto: CreateUomDto): Promise<Uom> {
    // Validate category exists
    await this.findCategoryById(dto.category_id);

    // Check unique code
    const existing = await queryOne<Uom>(
      `SELECT id FROM core.uom WHERE code = $1`,
      [dto.code]
    );
    if (existing) {
      throw new ConflictError(`Ya existe una UdM con código ${dto.code}`);
    }

    const uom = await queryOne<Uom>(
      `INSERT INTO core.uom (name, code, category_id, uom_type, ratio)
       VALUES ($1, $2, $3, $4, $5)
       RETURNING *`,
      [dto.name, dto.code, dto.category_id, dto.uom_type || 'reference', dto.ratio || 1]
    );
    return uom!;
  }

  async update(id: string, dto: UpdateUomDto): Promise<Uom> {
    await this.findById(id);

    const updateFields: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    if (dto.name !== undefined) {
      updateFields.push(`name = $${paramIndex++}`);
      values.push(dto.name);
    }
    if (dto.ratio !== undefined) {
      updateFields.push(`ratio = $${paramIndex++}`);
      values.push(dto.ratio);
    }
    if (dto.active !== undefined) {
      updateFields.push(`active = $${paramIndex++}`);
      values.push(dto.active);
    }

    if (updateFields.length === 0) {
      return this.findById(id);
    }

    values.push(id);
    const uom = await queryOne<Uom>(
      `UPDATE core.uom SET ${updateFields.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
      values
    );
    return uom!;
  }
}

export const uomService = new UomService();
