'use strict'

const { execute, queryOne, query } = require('../database/postgres')

class Pedido {
  static findById(id) {
    return queryOne(`
      SELECT p.*,
             COALESCE(cl.nome,     u.nome)  AS cliente_nome,
             COALESCE(cl.tipo,     'PF')    AS cliente_tipo,
             COALESCE(cl.cpf_cnpj, u.cpf)   AS cpf_cnpj,
             COALESCE(cl.email,    u.email)  AS cliente_email,
             COALESCE(e.rua,    p.end_rua)    AS rua,
             COALESCE(e.numero, p.end_numero) AS end_numero,
             COALESCE(e.bairro, p.end_bairro) AS bairro,
             COALESCE(e.cidade, p.end_cidade) AS cidade,
             COALESCE(e.estado, p.end_estado) AS estado,
             COALESCE(e.cep,    p.end_cep)    AS cep,
             ase.name AS separador_nome,
             aem.name AS embalador_nome,
             aau.name AS auditor_nome,
             afi.name AS fiscal_nome,
             aex.name AS expedidor_nome,
             acu.name AS cupom_emitido_por_nome
      FROM pedidos p
      LEFT JOIN clientes cl ON cl.id = p.cliente_id
      LEFT JOIN users    u  ON u.id  = p.user_id
      LEFT JOIN cliente_enderecos e ON e.id = p.endereco_id
      LEFT JOIN accounts ase ON ase.id = p.separador_id
      LEFT JOIN accounts aem ON aem.id = p.embalador_id
      LEFT JOIN accounts aau ON aau.id = p.auditor_id
      LEFT JOIN accounts afi ON afi.id = p.fiscal_id
      LEFT JOIN accounts aex ON aex.id = p.expedidor_id
      LEFT JOIN accounts acu ON acu.id = p.cupom_emitido_por
      WHERE p.id = $1
    `, [id])
  }

  static listFinanceiro(tenantId, { limit = 50, offset = 0 } = {}) {
    return query(
      `SELECT p.*,
              COALESCE(cl.nome,     u.nome)  AS cliente_nome,
              COALESCE(cl.tipo,     'PF')    AS cliente_tipo,
              COALESCE(cl.cpf_cnpj, u.cpf)   AS cpf_cnpj
       FROM pedidos p
       LEFT JOIN clientes cl ON cl.id = p.cliente_id
       LEFT JOIN users    u  ON u.id  = p.user_id
       WHERE p.tenant_id = $1 AND p.financeiro_status = 'pendente'
       ORDER BY p.created_at ASC
       LIMIT $2 OFFSET $3`,
      [tenantId, Math.min(Number(limit) || 50, 200), Math.max(Number(offset) || 0, 0)]
    )
  }

  static financeiroDecisao(id, { acao, obs }) {
    if (acao === 'aprovar') {
      return execute(
        `UPDATE pedidos SET financeiro_status='aprovado', financeiro_obs=$1, financeiro_em=NOW(), updated_at=NOW() WHERE id=$2`,
        [obs || null, id]
      )
    }
    // rejeitar → cancela o pedido
    return execute(
      `UPDATE pedidos SET financeiro_status='rejeitado', financeiro_obs=$1, financeiro_em=NOW(),
              status='cancelado', updated_at=NOW() WHERE id=$2`,
      [obs || null, id]
    )
  }

  static updateAddressInline(id, { cep, rua, numero, complemento, bairro, cidade, estado }) {
    return execute(
      `UPDATE pedidos SET end_cep=$1, end_rua=$2, end_numero=$3, end_complemento=$4,
              end_bairro=$5, end_cidade=$6, end_estado=$7, updated_at=NOW() WHERE id=$8`,
      [cep, rua, numero, complemento, bairro, cidade, estado, id]
    )
  }

  static listAdmin(tenantId, { status, from, to, limit = 50, offset = 0 } = {}) {
    const params = [tenantId]
    let where = 'WHERE p.tenant_id = $1'
    if (status) { params.push(status); where += ` AND p.status = $${params.length}` }
    if (from)   { params.push(from);   where += ` AND DATE(p.created_at) >= $${params.length}` }
    if (to)     { params.push(to);     where += ` AND DATE(p.created_at) <= $${params.length}` }
    params.push(Math.min(Number(limit) || 50, 200))
    params.push(Math.max(Number(offset) || 0, 0))
    return query(
      `SELECT p.*,
              COALESCE(cl.nome, u.nome) AS cliente_nome,
              COALESCE(cl.tipo, 'PF')   AS cliente_tipo
       FROM pedidos p
       LEFT JOIN clientes cl ON cl.id = p.cliente_id
       LEFT JOIN users    u  ON u.id  = p.user_id
       ${where} ORDER BY p.created_at DESC
       LIMIT $${params.length - 1} OFFSET $${params.length}`,
      params
    )
  }

  static listByCliente(clienteId, tenantId) {
    return query(
      `SELECT * FROM pedidos WHERE cliente_id = $1 AND tenant_id = $2 ORDER BY created_at DESC`,
      [clienteId, tenantId]
    )
  }

  static listItens(pedidoId) {
    return query(
      `SELECT pi.*, p.imagem AS produto_imagem
       FROM pedido_itens pi
       LEFT JOIN produtos p ON p.id = pi.produto_id
       WHERE pi.pedido_id = $1 ORDER BY pi.id ASC`,
      [pedidoId]
    )
  }

  // Retorna o log de quem executou cada etapa, com dados do colaborador
  static findHistorico(pedidoId) {
    return query(`
      SELECT psl.id, psl.status, psl.created_at AS feito_em,
             a.id AS account_id, a.name AS account_name,
             a.avatar_url AS account_avatar, a.role AS account_role
      FROM pedido_status_log psl
      LEFT JOIN accounts a ON a.id = psl.account_id
      WHERE psl.pedido_id = $1
      ORDER BY psl.created_at ASC
    `, [pedidoId])
  }

  static async logStatus(pedidoId, status, accountId = null) {
    try {
      await execute(
        'INSERT INTO pedido_status_log (pedido_id, status, account_id) VALUES ($1,$2,$3)',
        [pedidoId, status, accountId || null]
      )
    } catch { /* nunca bloqueia o fluxo principal */ }
  }

  static async updateStatus(id, status, accountId = null) {
    // Quando entra em expedição, registra o horário de saída do entregador.
    // Só seta uma vez (COALESCE preserva valor já existente em re-transições).
    if (status === 'expedicao') {
      await execute(
        `UPDATE pedidos
            SET status=$1,
                expedidor_saida_em = COALESCE(expedidor_saida_em, NOW()),
                expedidor_id       = COALESCE($2, expedidor_id),
                updated_at = NOW()
          WHERE id=$3`,
        [status, accountId || null, id]
      )
    } else {
      await execute('UPDATE pedidos SET status=$1, updated_at=NOW() WHERE id=$2', [status, id])
    }
    await Pedido.logStatus(id, status, accountId)
  }

  // Registra cupom fiscal emitido externamente (PDV/ECF).
  // numero: COO ou número do cupom. chave: chave de acesso NFC-e (44 dígitos).
  // accountId: quem clicou no botão (auditoria).
  static async registrarCupom(id, { numero, chave, accountId }) {
    await execute(
      `UPDATE pedidos
          SET cupom_numero      = $1,
              cupom_chave       = $2,
              cupom_emitido_em  = NOW(),
              cupom_emitido_por = $3,
              updated_at = NOW()
        WHERE id = $4`,
      [numero || null, chave || null, accountId || null, id]
    )
  }

  static atribuirEquipe(id, equipeId) {
    return execute('UPDATE pedidos SET equipe_id=$1, updated_at=NOW() WHERE id=$2', [equipeId, id])
  }

  static async marcarEntregue(id, responsavel, accountId = null) {
    const expedidorId = accountId || null
    await execute(
      `UPDATE pedidos
          SET status=$1, responsavel_entrega=$2, expedidor_id=$3, entregue_em=NOW(), updated_at=NOW()
        WHERE id=$4`,
      ['entregue', responsavel || null, expedidorId, id]
    )
    await Pedido.logStatus(id, 'entregue', accountId)
  }

  static marcarItemSeparado(itemId, separado) {
    return execute('UPDATE pedido_itens SET separado=$1 WHERE id=$2', [separado, itemId])
  }

  static setAlertaItem(itemId, { tipo, obs, foto }) {
    return execute(
      `UPDATE pedido_itens
         SET alerta_tipo=$1, alerta_obs=$2, alerta_foto=$3,
             alerta_confirmado=FALSE, alerta_em=NOW()
       WHERE id=$4`,
      [tipo || null, obs || null, foto || null, itemId]
    )
  }

  static confirmarAlertaItem(itemId) {
    return execute(
      `UPDATE pedido_itens SET alerta_confirmado=TRUE WHERE id=$1`, [itemId]
    )
  }

  static limparAlertaItem(itemId) {
    return execute(
      `UPDATE pedido_itens
         SET alerta_tipo=NULL, alerta_obs=NULL, alerta_foto=NULL,
             alerta_confirmado=FALSE, alerta_em=NULL
       WHERE id=$1`,
      [itemId]
    )
  }

  // EMB-02 — registra embalador (texto legado) + embalador_id (FK) e timestamp
  static async marcarEmbalado(id, embalador, accountId = null) {
    // embalador_id prevalece sobre texto livre; accountId é o id do colaborador logado
    const embaladorId = accountId || null
    await execute(
      `UPDATE pedidos
          SET status=$1, embalador=$2, embalador_id=$3, embalado_em=NOW(), updated_at=NOW()
        WHERE id=$4`,
      ['embalagem', embalador || null, embaladorId, id]
    )
    await Pedido.logStatus(id, 'embalagem', accountId)
  }

  // Atribui um colaborador como responsável por uma etapa (separador/auditor/fiscal).
  // Para embalador/expedidor existem métodos dedicados (marcarEmbalado/marcarEntregue)
  // por terem efeitos colaterais — mudança de status, timestamps e notificações.
  // Mapeia funcao → coluna de FK; rejeita funções desconhecidas (segurança contra SQLi).
  static async setResponsavel(id, funcao, accountId) {
    const COL = { separador: 'separador_id', auditor: 'auditor_id', fiscal: 'fiscal_id' }
    const col = COL[funcao]
    if (!col) throw new Error(`Função inválida: ${funcao}`)
    await execute(`UPDATE pedidos SET ${col}=$1, updated_at=NOW() WHERE id=$2`, [accountId || null, id])
  }

  // DASH-04 — notificações internas (novos pedidos/cotações recentes)
  static notificacoes(tenantId, limitMinutes = 1440) {
    return query(`
      SELECT id, status, total, cliente_id, created_at,
             'pedido' AS tipo
      FROM pedidos
      WHERE tenant_id = $1
        AND created_at >= NOW() - ($2 || ' minutes')::INTERVAL
      ORDER BY created_at DESC
      LIMIT 30
    `, [tenantId, limitMinutes])
  }

  // Contadores para dashboard
  static contadores(tenantId) {
    return queryOne(`
      SELECT
        COUNT(*) FILTER (WHERE DATE(created_at) = CURRENT_DATE)                              AS hoje,
        COUNT(*) FILTER (WHERE status = 'aguardando')                                        AS aguardando,
        COUNT(*) FILTER (WHERE status = 'separacao')                                         AS em_separacao,
        COUNT(*) FILTER (WHERE status = 'embalagem')                                         AS em_embalagem,
        COUNT(*) FILTER (WHERE status = 'auditoria')                                         AS em_auditoria,
        COUNT(*) FILTER (WHERE status IN ('fiscal','expedicao'))                              AS prontos,
        COUNT(*) FILTER (WHERE status = 'entregue')                                          AS entregues,
        COUNT(*) FILTER (WHERE status NOT IN ('entregue','cancelado'))                        AS em_aberto,
        COUNT(*) FILTER (WHERE financeiro_status = 'pendente')                               AS financeiro_pendente
      FROM pedidos WHERE tenant_id = $1
    `, [tenantId])
  }
}

module.exports = Pedido
