import { query, queryOne, getClient } from '../../config/database.js';
import { NotFoundError, ConflictError, ValidationError } from '../../shared/errors/index.js';
import { taxesService } from '../financial/taxes.service.js';
import { emailService } from '../../shared/services/email.service.js';
import { logger } from '../../shared/utils/logger.js';

export interface QuotationLine {
  id: string;
  quotation_id: string;
  product_id?: string;
  product_name?: string;
  description: string;
  quantity: number;
  uom_id: string;
  uom_name?: string;
  price_unit: number;
  discount: number;
  tax_ids: string[];
  amount_untaxed: number;
  amount_tax: number;
  amount_total: number;
}

export interface Quotation {
  id: string;
  tenant_id: string;
  company_id: string;
  company_name?: string;
  name: string;
  partner_id: string;
  partner_name?: string;
  quotation_date: Date;
  validity_date: Date;
  currency_id: string;
  currency_code?: string;
  pricelist_id?: string;
  pricelist_name?: string;
  user_id?: string;
  user_name?: string;
  sales_team_id?: string;
  sales_team_name?: string;
  amount_untaxed: number;
  amount_tax: number;
  amount_total: number;
  status: 'draft' | 'sent' | 'confirmed' | 'cancelled' | 'expired';
  sale_order_id?: string;
  notes?: string;
  terms_conditions?: string;
  lines?: QuotationLine[];
  created_at: Date;
}

export interface CreateQuotationDto {
  company_id: string;
  partner_id: string;
  quotation_date?: string;
  validity_date: string;
  currency_id: string;
  pricelist_id?: string;
  sales_team_id?: string;
  notes?: string;
  terms_conditions?: string;
}

export interface UpdateQuotationDto {
  partner_id?: string;
  quotation_date?: string;
  validity_date?: string;
  currency_id?: string;
  pricelist_id?: string | null;
  sales_team_id?: string | null;
  notes?: string | null;
  terms_conditions?: string | null;
}

export interface CreateQuotationLineDto {
  product_id?: string;
  description: string;
  quantity: number;
  uom_id: string;
  price_unit: number;
  discount?: number;
  tax_ids?: string[];
}

export interface UpdateQuotationLineDto {
  description?: string;
  quantity?: number;
  uom_id?: string;
  price_unit?: number;
  discount?: number;
  tax_ids?: string[];
}

export interface QuotationFilters {
  company_id?: string;
  partner_id?: string;
  status?: string;
  date_from?: string;
  date_to?: string;
  search?: string;
  page?: number;
  limit?: number;
}

class QuotationsService {
  async findAll(tenantId: string, filters: QuotationFilters = {}): Promise<{ data: Quotation[]; total: number }> {
    const { company_id, partner_id, status, date_from, date_to, search, page = 1, limit = 20 } = filters;
    const offset = (page - 1) * limit;

    let whereClause = 'WHERE q.tenant_id = $1';
    const params: any[] = [tenantId];
    let paramIndex = 2;

    if (company_id) {
      whereClause += ` AND q.company_id = $${paramIndex++}`;
      params.push(company_id);
    }

    if (partner_id) {
      whereClause += ` AND q.partner_id = $${paramIndex++}`;
      params.push(partner_id);
    }

    if (status) {
      whereClause += ` AND q.status = $${paramIndex++}`;
      params.push(status);
    }

    if (date_from) {
      whereClause += ` AND q.quotation_date >= $${paramIndex++}`;
      params.push(date_from);
    }

    if (date_to) {
      whereClause += ` AND q.quotation_date <= $${paramIndex++}`;
      params.push(date_to);
    }

    if (search) {
      whereClause += ` AND (q.name ILIKE $${paramIndex} OR p.name ILIKE $${paramIndex})`;
      params.push(`%${search}%`);
      paramIndex++;
    }

    const countResult = await queryOne<{ count: string }>(
      `SELECT COUNT(*) as count
       FROM sales.quotations q
       LEFT JOIN core.partners p ON q.partner_id = p.id
       ${whereClause}`,
      params
    );

    params.push(limit, offset);
    const data = await query<Quotation>(
      `SELECT q.*,
              c.name as company_name,
              p.name as partner_name,
              cu.code as currency_code,
              pl.name as pricelist_name,
              u.name as user_name,
              st.name as sales_team_name
       FROM sales.quotations q
       LEFT JOIN auth.companies c ON q.company_id = c.id
       LEFT JOIN core.partners p ON q.partner_id = p.id
       LEFT JOIN core.currencies cu ON q.currency_id = cu.id
       LEFT JOIN sales.pricelists pl ON q.pricelist_id = pl.id
       LEFT JOIN auth.users u ON q.user_id = u.id
       LEFT JOIN sales.sales_teams st ON q.sales_team_id = st.id
       ${whereClause}
       ORDER BY q.created_at DESC
       LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
      params
    );

    return {
      data,
      total: parseInt(countResult?.count || '0', 10),
    };
  }

  async findById(id: string, tenantId: string): Promise<Quotation> {
    const quotation = await queryOne<Quotation>(
      `SELECT q.*,
              c.name as company_name,
              p.name as partner_name,
              cu.code as currency_code,
              pl.name as pricelist_name,
              u.name as user_name,
              st.name as sales_team_name
       FROM sales.quotations q
       LEFT JOIN auth.companies c ON q.company_id = c.id
       LEFT JOIN core.partners p ON q.partner_id = p.id
       LEFT JOIN core.currencies cu ON q.currency_id = cu.id
       LEFT JOIN sales.pricelists pl ON q.pricelist_id = pl.id
       LEFT JOIN auth.users u ON q.user_id = u.id
       LEFT JOIN sales.sales_teams st ON q.sales_team_id = st.id
       WHERE q.id = $1 AND q.tenant_id = $2`,
      [id, tenantId]
    );

    if (!quotation) {
      throw new NotFoundError('Cotización no encontrada');
    }

    // Get lines
    const lines = await query<QuotationLine>(
      `SELECT ql.*,
              pr.name as product_name,
              um.name as uom_name
       FROM sales.quotation_lines ql
       LEFT JOIN inventory.products pr ON ql.product_id = pr.id
       LEFT JOIN core.uom um ON ql.uom_id = um.id
       WHERE ql.quotation_id = $1
       ORDER BY ql.created_at`,
      [id]
    );

    quotation.lines = lines;

    return quotation;
  }

  async create(dto: CreateQuotationDto, tenantId: string, userId: string): Promise<Quotation> {
    // Generate sequence number
    const seqResult = await queryOne<{ next_num: number }>(
      `SELECT COALESCE(MAX(CAST(SUBSTRING(name FROM 5) AS INTEGER)), 0) + 1 as next_num
       FROM sales.quotations WHERE tenant_id = $1 AND name LIKE 'QUO-%'`,
      [tenantId]
    );
    const quotationNumber = `QUO-${String(seqResult?.next_num || 1).padStart(6, '0')}`;

    const quotationDate = dto.quotation_date || new Date().toISOString().split('T')[0];

    const quotation = await queryOne<Quotation>(
      `INSERT INTO sales.quotations (
        tenant_id, company_id, name, partner_id, quotation_date, validity_date,
        currency_id, pricelist_id, user_id, sales_team_id, notes, terms_conditions, created_by
      )
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
       RETURNING *`,
      [
        tenantId, dto.company_id, quotationNumber, dto.partner_id,
        quotationDate, dto.validity_date, dto.currency_id, dto.pricelist_id,
        userId, dto.sales_team_id, dto.notes, dto.terms_conditions, userId
      ]
    );

    return quotation!;
  }

  async update(id: string, dto: UpdateQuotationDto, tenantId: string, userId: string): Promise<Quotation> {
    const existing = await this.findById(id, tenantId);

    if (existing.status !== 'draft') {
      throw new ValidationError('Solo se pueden editar cotizaciones en estado borrador');
    }

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

    if (dto.partner_id !== undefined) {
      updateFields.push(`partner_id = $${paramIndex++}`);
      values.push(dto.partner_id);
    }
    if (dto.quotation_date !== undefined) {
      updateFields.push(`quotation_date = $${paramIndex++}`);
      values.push(dto.quotation_date);
    }
    if (dto.validity_date !== undefined) {
      updateFields.push(`validity_date = $${paramIndex++}`);
      values.push(dto.validity_date);
    }
    if (dto.currency_id !== undefined) {
      updateFields.push(`currency_id = $${paramIndex++}`);
      values.push(dto.currency_id);
    }
    if (dto.pricelist_id !== undefined) {
      updateFields.push(`pricelist_id = $${paramIndex++}`);
      values.push(dto.pricelist_id);
    }
    if (dto.sales_team_id !== undefined) {
      updateFields.push(`sales_team_id = $${paramIndex++}`);
      values.push(dto.sales_team_id);
    }
    if (dto.notes !== undefined) {
      updateFields.push(`notes = $${paramIndex++}`);
      values.push(dto.notes);
    }
    if (dto.terms_conditions !== undefined) {
      updateFields.push(`terms_conditions = $${paramIndex++}`);
      values.push(dto.terms_conditions);
    }

    if (updateFields.length === 0) {
      return existing;
    }

    updateFields.push(`updated_by = $${paramIndex++}`);
    values.push(userId);
    updateFields.push(`updated_at = CURRENT_TIMESTAMP`);

    values.push(id, tenantId);

    await query(
      `UPDATE sales.quotations SET ${updateFields.join(', ')}
       WHERE id = $${paramIndex++} AND tenant_id = $${paramIndex}`,
      values
    );

    return this.findById(id, tenantId);
  }

  async delete(id: string, tenantId: string): Promise<void> {
    const existing = await this.findById(id, tenantId);

    if (existing.status !== 'draft') {
      throw new ValidationError('Solo se pueden eliminar cotizaciones en estado borrador');
    }

    await query(
      `DELETE FROM sales.quotations WHERE id = $1 AND tenant_id = $2`,
      [id, tenantId]
    );
  }

  async addLine(quotationId: string, dto: CreateQuotationLineDto, tenantId: string, userId: string): Promise<QuotationLine> {
    const quotation = await this.findById(quotationId, tenantId);

    if (quotation.status !== 'draft') {
      throw new ValidationError('Solo se pueden agregar líneas a cotizaciones en estado borrador');
    }

    // Calculate amounts with taxes using taxesService
    const taxResult = await taxesService.calculateTaxes(
      {
        quantity: dto.quantity,
        priceUnit: dto.price_unit,
        discount: dto.discount || 0,
        taxIds: dto.tax_ids || [],
      },
      tenantId,
      'sales'
    );
    const amountUntaxed = taxResult.amountUntaxed;
    const amountTax = taxResult.amountTax;
    const amountTotal = taxResult.amountTotal;

    const line = await queryOne<QuotationLine>(
      `INSERT INTO sales.quotation_lines (
        quotation_id, tenant_id, product_id, description, quantity, uom_id,
        price_unit, discount, tax_ids, amount_untaxed, amount_tax, amount_total
      )
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
       RETURNING *`,
      [
        quotationId, tenantId, dto.product_id, dto.description, dto.quantity, dto.uom_id,
        dto.price_unit, dto.discount || 0, dto.tax_ids || [], amountUntaxed, amountTax, amountTotal
      ]
    );

    // Update quotation totals
    await this.updateTotals(quotationId);

    return line!;
  }

  async updateLine(quotationId: string, lineId: string, dto: UpdateQuotationLineDto, tenantId: string): Promise<QuotationLine> {
    const quotation = await this.findById(quotationId, tenantId);

    if (quotation.status !== 'draft') {
      throw new ValidationError('Solo se pueden editar líneas de cotizaciones en estado borrador');
    }

    const existingLine = quotation.lines?.find(l => l.id === lineId);
    if (!existingLine) {
      throw new NotFoundError('Línea de cotización no encontrada');
    }

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

    const quantity = dto.quantity ?? existingLine.quantity;
    const priceUnit = dto.price_unit ?? existingLine.price_unit;
    const discount = dto.discount ?? existingLine.discount;

    if (dto.description !== undefined) {
      updateFields.push(`description = $${paramIndex++}`);
      values.push(dto.description);
    }
    if (dto.quantity !== undefined) {
      updateFields.push(`quantity = $${paramIndex++}`);
      values.push(dto.quantity);
    }
    if (dto.uom_id !== undefined) {
      updateFields.push(`uom_id = $${paramIndex++}`);
      values.push(dto.uom_id);
    }
    if (dto.price_unit !== undefined) {
      updateFields.push(`price_unit = $${paramIndex++}`);
      values.push(dto.price_unit);
    }
    if (dto.discount !== undefined) {
      updateFields.push(`discount = $${paramIndex++}`);
      values.push(dto.discount);
    }
    if (dto.tax_ids !== undefined) {
      updateFields.push(`tax_ids = $${paramIndex++}`);
      values.push(dto.tax_ids);
    }

    // Recalculate amounts using taxesService
    const taxIds = dto.tax_ids ?? existingLine.tax_ids;
    const taxResult = await taxesService.calculateTaxes(
      {
        quantity,
        priceUnit,
        discount,
        taxIds,
      },
      tenantId,
      'sales'
    );
    const amountUntaxed = taxResult.amountUntaxed;
    const amountTax = taxResult.amountTax;
    const amountTotal = taxResult.amountTotal;

    updateFields.push(`amount_untaxed = $${paramIndex++}`);
    values.push(amountUntaxed);
    updateFields.push(`amount_tax = $${paramIndex++}`);
    values.push(amountTax);
    updateFields.push(`amount_total = $${paramIndex++}`);
    values.push(amountTotal);

    values.push(lineId, quotationId);

    await query(
      `UPDATE sales.quotation_lines SET ${updateFields.join(', ')}
       WHERE id = $${paramIndex++} AND quotation_id = $${paramIndex}`,
      values
    );

    // Update quotation totals
    await this.updateTotals(quotationId);

    const updated = await queryOne<QuotationLine>(
      `SELECT * FROM sales.quotation_lines WHERE id = $1`,
      [lineId]
    );

    return updated!;
  }

  async removeLine(quotationId: string, lineId: string, tenantId: string): Promise<void> {
    const quotation = await this.findById(quotationId, tenantId);

    if (quotation.status !== 'draft') {
      throw new ValidationError('Solo se pueden eliminar líneas de cotizaciones en estado borrador');
    }

    await query(
      `DELETE FROM sales.quotation_lines WHERE id = $1 AND quotation_id = $2`,
      [lineId, quotationId]
    );

    // Update quotation totals
    await this.updateTotals(quotationId);
  }

  async send(id: string, tenantId: string, userId: string): Promise<Quotation> {
    const quotation = await this.findById(id, tenantId);

    if (quotation.status !== 'draft') {
      throw new ValidationError('Solo se pueden enviar cotizaciones en estado borrador');
    }

    if (!quotation.lines || quotation.lines.length === 0) {
      throw new ValidationError('La cotización debe tener al menos una línea');
    }

    await query(
      `UPDATE sales.quotations SET status = 'sent', updated_by = $1, updated_at = CURRENT_TIMESTAMP
       WHERE id = $2 AND tenant_id = $3`,
      [userId, id, tenantId]
    );

    // Send email notification to partner
    await this.sendQuotationEmail(quotation, tenantId);

    return this.findById(id, tenantId);
  }

  /**
   * Send quotation email to partner
   */
  private async sendQuotationEmail(quotation: Quotation, tenantId: string): Promise<void> {
    try {
      // Get partner email
      const partner = await queryOne<{ name: string; email: string | null }>(
        `SELECT name, email FROM core.partners WHERE id = $1 AND tenant_id = $2`,
        [quotation.partner_id, tenantId]
      );

      if (!partner?.email) {
        logger.warn('Partner has no email, skipping quotation notification', {
          quotationId: quotation.id,
          partnerId: quotation.partner_id,
        });
        return;
      }

      // Get company info for the email
      const company = await queryOne<{ name: string }>(
        `SELECT name FROM auth.companies WHERE id = $1`,
        [quotation.company_id]
      );

      const html = this.generateQuotationEmailTemplate({
        quotationName: quotation.name,
        partnerName: partner.name,
        companyName: company?.name || 'ERP Core',
        validityDate: quotation.validity_date,
        amountTotal: quotation.amount_total,
        currencyCode: quotation.currency_code || 'MXN',
        lines: quotation.lines || [],
      });

      const result = await emailService.send({
        to: partner.email,
        subject: `Cotización ${quotation.name} - ${company?.name || 'ERP Core'}`,
        html,
        text: `Estimado/a ${partner.name},\n\nLe enviamos la cotización ${quotation.name} por un total de ${quotation.currency_code || 'MXN'} ${quotation.amount_total.toLocaleString()}.\n\nEsta cotización es válida hasta ${new Date(quotation.validity_date).toLocaleDateString('es-MX')}.\n\nSaludos,\n${company?.name || 'ERP Core'}`,
      });

      if (result.success) {
        logger.info('Quotation email sent successfully', {
          quotationId: quotation.id,
          partnerEmail: partner.email,
          messageId: result.messageId,
        });
      } else {
        logger.error('Failed to send quotation email', {
          quotationId: quotation.id,
          error: result.error,
        });
      }
    } catch (error) {
      // Don't fail the send operation if email fails
      logger.error('Error sending quotation email', {
        quotationId: quotation.id,
        error: (error as Error).message,
      });
    }
  }

  /**
   * Generate HTML template for quotation email
   */
  private generateQuotationEmailTemplate(params: {
    quotationName: string;
    partnerName: string;
    companyName: string;
    validityDate: Date;
    amountTotal: number;
    currencyCode: string;
    lines: QuotationLine[];
  }): string {
    const { quotationName, partnerName, companyName, validityDate, amountTotal, currencyCode, lines } = params;
    const supportEmail = process.env.SUPPORT_EMAIL || 'ventas@erp-core.local';

    const linesHtml = lines.map(line => `
      <tr>
        <td style="padding: 12px; border-bottom: 1px solid #e5e7eb;">${line.description}</td>
        <td style="padding: 12px; border-bottom: 1px solid #e5e7eb; text-align: center;">${line.quantity}</td>
        <td style="padding: 12px; border-bottom: 1px solid #e5e7eb; text-align: right;">${currencyCode} ${line.price_unit.toLocaleString()}</td>
        <td style="padding: 12px; border-bottom: 1px solid #e5e7eb; text-align: right;">${currencyCode} ${line.amount_total.toLocaleString()}</td>
      </tr>
    `).join('');

    return `
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Cotización ${quotationName}</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
      line-height: 1.6;
      color: #333;
      max-width: 700px;
      margin: 0 auto;
      padding: 20px;
      background-color: #f5f5f5;
    }
    .container {
      background-color: #ffffff;
      border-radius: 8px;
      padding: 40px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }
    .header {
      text-align: center;
      margin-bottom: 30px;
      padding-bottom: 20px;
      border-bottom: 2px solid #2563eb;
    }
    .logo {
      font-size: 24px;
      font-weight: bold;
      color: #2563eb;
    }
    h1 {
      color: #1f2937;
      font-size: 22px;
      margin-bottom: 20px;
    }
    p {
      margin-bottom: 16px;
      color: #4b5563;
    }
    .quote-info {
      background-color: #f9fafb;
      border-radius: 8px;
      padding: 20px;
      margin: 20px 0;
    }
    .quote-info-row {
      display: flex;
      justify-content: space-between;
      margin-bottom: 8px;
    }
    .quote-info-label {
      color: #6b7280;
      font-weight: 500;
    }
    .quote-info-value {
      color: #1f2937;
      font-weight: 600;
    }
    table {
      width: 100%;
      border-collapse: collapse;
      margin: 20px 0;
    }
    th {
      background-color: #f3f4f6;
      padding: 12px;
      text-align: left;
      font-weight: 600;
      color: #374151;
      border-bottom: 2px solid #e5e7eb;
    }
    th:last-child, th:nth-child(3), th:nth-child(2) {
      text-align: right;
    }
    th:nth-child(2) {
      text-align: center;
    }
    .total-row {
      background-color: #2563eb;
      color: white;
    }
    .total-row td {
      padding: 14px 12px;
      font-weight: 600;
      border-bottom: none;
    }
    .validity {
      background-color: #fef3c7;
      border-left: 4px solid #f59e0b;
      padding: 12px 16px;
      margin: 20px 0;
      border-radius: 0 4px 4px 0;
    }
    .footer {
      margin-top: 40px;
      padding-top: 20px;
      border-top: 1px solid #e5e7eb;
      font-size: 14px;
      color: #6b7280;
      text-align: center;
    }
    .contact-link {
      color: #2563eb;
      text-decoration: none;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="header">
      <div class="logo">${companyName}</div>
    </div>

    <h1>Cotización ${quotationName}</h1>

    <p>Estimado/a <strong>${partnerName}</strong>,</p>

    <p>Le enviamos nuestra cotización según lo solicitado. A continuación encontrará el detalle de los productos y/o servicios cotizados:</p>

    <table>
      <thead>
        <tr>
          <th>Descripción</th>
          <th>Cantidad</th>
          <th>Precio Unit.</th>
          <th>Subtotal</th>
        </tr>
      </thead>
      <tbody>
        ${linesHtml}
        <tr class="total-row">
          <td colspan="3" style="text-align: right;">TOTAL:</td>
          <td style="text-align: right;">${currencyCode} ${amountTotal.toLocaleString()}</td>
        </tr>
      </tbody>
    </table>

    <div class="validity">
      <strong>Vigencia:</strong> Esta cotización es válida hasta el ${new Date(validityDate).toLocaleDateString('es-MX', { year: 'numeric', month: 'long', day: 'numeric' })}.
    </div>

    <p>Si tiene alguna pregunta o desea proceder con el pedido, no dude en contactarnos.</p>

    <div class="footer">
      <p>Atentamente,<br><strong>${companyName}</strong></p>
      <p>Para cualquier consulta, contáctenos en <a href="mailto:${supportEmail}" class="contact-link">${supportEmail}</a></p>
      <p>&copy; ${new Date().getFullYear()} ${companyName}. Todos los derechos reservados.</p>
    </div>
  </div>
</body>
</html>
    `.trim();
  }

  async confirm(id: string, tenantId: string, userId: string): Promise<{ quotation: Quotation; orderId: string }> {
    const quotation = await this.findById(id, tenantId);

    if (!['draft', 'sent'].includes(quotation.status)) {
      throw new ValidationError('Solo se pueden confirmar cotizaciones en estado borrador o enviado');
    }

    if (!quotation.lines || quotation.lines.length === 0) {
      throw new ValidationError('La cotización debe tener al menos una línea');
    }

    const client = await getClient();
    try {
      await client.query('BEGIN');

      // Generate order sequence number
      const seqResult = await client.query(
        `SELECT COALESCE(MAX(CAST(SUBSTRING(name FROM 4) AS INTEGER)), 0) + 1 as next_num
         FROM sales.sales_orders WHERE tenant_id = $1 AND name LIKE 'SO-%'`,
        [tenantId]
      );
      const orderNumber = `SO-${String(seqResult.rows[0]?.next_num || 1).padStart(6, '0')}`;

      // Create sales order
      const orderResult = await client.query(
        `INSERT INTO sales.sales_orders (
          tenant_id, company_id, name, partner_id, order_date, currency_id,
          pricelist_id, user_id, sales_team_id, amount_untaxed, amount_tax,
          amount_total, notes, terms_conditions, created_by
        )
         SELECT tenant_id, company_id, $1, partner_id, CURRENT_DATE, currency_id,
                pricelist_id, user_id, sales_team_id, amount_untaxed, amount_tax,
                amount_total, notes, terms_conditions, $2
         FROM sales.quotations WHERE id = $3
         RETURNING id`,
        [orderNumber, userId, id]
      );
      const orderId = orderResult.rows[0].id;

      // Copy lines to order (include tenant_id for multi-tenant security)
      await client.query(
        `INSERT INTO sales.sales_order_lines (
          order_id, tenant_id, product_id, description, quantity, uom_id, price_unit,
          discount, tax_ids, amount_untaxed, amount_tax, amount_total
        )
         SELECT $1, $3, product_id, description, quantity, uom_id, price_unit,
                discount, tax_ids, amount_untaxed, amount_tax, amount_total
         FROM sales.quotation_lines WHERE quotation_id = $2 AND tenant_id = $3`,
        [orderId, id, tenantId]
      );

      // Update quotation status
      await client.query(
        `UPDATE sales.quotations SET status = 'confirmed', sale_order_id = $1,
         updated_by = $2, updated_at = CURRENT_TIMESTAMP
         WHERE id = $3`,
        [orderId, userId, id]
      );

      await client.query('COMMIT');

      return {
        quotation: await this.findById(id, tenantId),
        orderId
      };
    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  }

  async cancel(id: string, tenantId: string, userId: string): Promise<Quotation> {
    const quotation = await this.findById(id, tenantId);

    if (quotation.status === 'confirmed') {
      throw new ValidationError('No se pueden cancelar cotizaciones confirmadas');
    }

    if (quotation.status === 'cancelled') {
      throw new ValidationError('La cotización ya está cancelada');
    }

    await query(
      `UPDATE sales.quotations SET status = 'cancelled', updated_by = $1, updated_at = CURRENT_TIMESTAMP
       WHERE id = $2 AND tenant_id = $3`,
      [userId, id, tenantId]
    );

    return this.findById(id, tenantId);
  }

  private async updateTotals(quotationId: string): Promise<void> {
    await query(
      `UPDATE sales.quotations SET
         amount_untaxed = COALESCE((SELECT SUM(amount_untaxed) FROM sales.quotation_lines WHERE quotation_id = $1), 0),
         amount_tax = COALESCE((SELECT SUM(amount_tax) FROM sales.quotation_lines WHERE quotation_id = $1), 0),
         amount_total = COALESCE((SELECT SUM(amount_total) FROM sales.quotation_lines WHERE quotation_id = $1), 0)
       WHERE id = $1`,
      [quotationId]
    );
  }
}

export const quotationsService = new QuotationsService();
