const Raffle         = require('../models/Raffle')
const Ticket         = require('../models/Ticket')
const RaffleResult   = require('../models/RaffleResult')
const Order          = require('../models/Order')
const PriceRule      = require('../models/PriceRule')
const RaffleDiscount   = require('../models/RaffleDiscount')
const RaffleFlashPromo = require('../models/RaffleFlashPromo')
const WhatsappCore   = require('../services/whatsappService')
const NotificationService = require('../services/notificationService')
const AsaasService   = require('../services/asaasService')
const crypto         = require('crypto')

function validateCPF(cpf) {
  cpf = cpf.replace(/[^\d]+/g, '')
  if (cpf.length !== 11 || /^(\d)\1{10}$/.test(cpf)) return false
  let sum = 0
  for (let i = 0; i < 9; i++) sum += parseInt(cpf.charAt(i)) * (10 - i)
  let rem = 11 - (sum % 11)
  if (rem === 10 || rem === 11) rem = 0
  if (rem !== parseInt(cpf.charAt(9))) return false
  sum = 0
  for (let i = 0; i < 10; i++) sum += parseInt(cpf.charAt(i)) * (11 - i)
  rem = 11 - (sum % 11)
  if (rem === 10 || rem === 11) rem = 0
  return rem === parseInt(cpf.charAt(10))
}

const raffleController = {
  async getRaffles(req, res) {
    try {
      const raffles = await Raffle.findActive(req.tenant?.id)
      return res.json(raffles)
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async getRaffleDetail(req, res) {
    try {
      const raffle = await Raffle.findById(req.params.id)
      if (!raffle) return res.status(404).json({ error: 'Sorteio não encontrado' })

      const soldNumbers   = await Ticket.getSoldNumbers(raffle.id)
      const totalSold     = soldNumbers.length

      return res.json({
        ...raffle,
        soldNumbers,
        totalSold,
        totalDisponivel: raffle.total_numeros - totalSold
      })
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async buyTicket(req, res) {
    try {
      const { raffle_id, numero, usuario_nome, usuario_telefone, usuario_cpf } = req.body

      if (!raffle_id || !numero || !usuario_nome) {
        return res.status(400).json({ error: 'Dados incompletos' })
      }

      if (usuario_cpf) {
        if (!validateCPF(usuario_cpf)) {
          return res.status(400).json({ error: 'CPF inválido' })
        }
      } else {
        return res.status(400).json({ error: 'CPF é obrigatório para pagamento via PIX' })
      }

      const raffle = await Raffle.findById(raffle_id)
      if (!raffle) throw new Error('Sorteio não encontrado')

      const localOrderId = crypto.randomUUID()
      const numeros = Array.isArray(numero) ? numero.map(n => parseInt(n)) : [parseInt(numero)]
      
      // ENGINE DE PRECIFICAÇÃO DINÂMICA
      const currentPriceData = await PriceRule.getCurrentPrice(raffle_id)
      const ticketPrice = currentPriceData.price

      // DESCONTO POR QUANTIDADE
      const bestDiscount = await RaffleDiscount.getBestForQty(raffle_id, numeros.length)
      const qtyDiscountPct = bestDiscount ? Number(bestDiscount.discount_pct) : 0

      // PROMOÇÃO RELÂMPAGO (aplica o maior entre os dois)
      const flashPromo   = await RaffleFlashPromo.getActive(raffle_id)
      const flashPct     = flashPromo ? Number(flashPromo.discount_pct) : 0
      const discountPct  = Math.max(qtyDiscountPct, flashPct)
      const discountType = flashPct >= qtyDiscountPct && flashPct > 0 ? 'flash' : (qtyDiscountPct > 0 ? 'quantity' : 'none')

      const subtotal = ticketPrice * numeros.length
      const amount   = discountPct > 0
        ? Math.round(subtotal * (1 - discountPct / 100) * 100) / 100
        : subtotal

      // 1. Cria Record de Order
      await Order.create({
        id: localOrderId,
        user_cpf: usuario_cpf.replace(/\D/g, ''),
        total_amount: amount,
        payment_method: 'PIX'
      })

      // 2. Tenta fazer a reserva — se falhar, remove a Order criada acima
      try {
        await Ticket.reserve({
          raffle_id,
          numeros,
          usuario_nome,
          usuario_telefone: usuario_telefone || null,
          usuario_cpf:      usuario_cpf.replace(/\D/g, ''),
          order_id:         localOrderId,
          preco_pago:       ticketPrice
        })
      } catch (reserveErr) {
        await Order.delete(localOrderId).catch(() => {})
        throw reserveErr
      }

      // 2.5 Registrar audit log do preço aplicado
      await PriceRule.logPrice({
        raffle_id,
        order_id:      localOrderId,
        user_cpf:      usuario_cpf.replace(/\D/g, ''),
        price_applied: ticketPrice,
        rule_id:       currentPriceData.rule_id
      })

      // 3. Se chegou aqui, os tickets estão reservados. Vamos chamar a Asaas
      let asaasPayload = null
      try {
        const customerId = await AsaasService.getOrCreateCustomer(
          usuario_nome, usuario_cpf, usuario_telefone, null
        )
        asaasPayload = await AsaasService.createPixCharge(
          customerId, amount, `Compra de ${numeros.length} rifa(s) no sorteio #${raffle_id}`
        )
      } catch (asaasErr) {
        throw new Error('Falha na comunicação com gateway de pagamento: ' + asaasErr.message)
      }

      // 4. Salva os IDs e dados Pix asaas
      await Order.updateAsaasPayment(
        localOrderId, asaasPayload.orderId, asaasPayload.qrCodeUrl, asaasPayload.pixCopyPaste
      )

      // Fase 7: Dispara notificação PIX Pendente via fila
      if (usuario_telefone && usuario_telefone.length >= 10) {
        WhatsappCore.sendNotification({
            userId: null, 
            phone: usuario_telefone,
            type: 'purchase_pending',
            variables: {
                pixCopiaECola: asaasPayload.pixCopyPaste,
                link: asaasPayload.qrCodeUrl
            }
        }).catch(console.error)
      }

      console.log(`🎟️ Tickets reservado para ${usuario_nome}. Custo: R$${amount.toFixed(2)}${discountPct > 0 ? ` (${discountPct}% off via ${discountType})` : ''} / PIX gerado`)
      return res.json({
        success: true,
        orderId: localOrderId,
        number: numero,
        amount,
        discountPct,
        discountType,
        subtotal,
        qrCodeUrl: asaasPayload.qrCodeUrl,
        pixCopyPaste: asaasPayload.pixCopyPaste
      })
    } catch (error) {
      if (error.message === 'Número já vendido')       return res.status(400).json({ error: 'Número já vendido ou reservado' })
      if (error.message === 'Sorteio não encontrado')  return res.status(404).json({ error: 'Sorteio não encontrado' })
      if (error.message === 'Sorteio encerrado')       return res.status(400).json({ error: 'Sorteio encerrado' })
      if (error.message.includes('Número inválido'))   return res.status(400).json({ error: error.message })
      if (error.code === '23505') return res.status(400).json({ error: 'Número já vendido ou reservado' })
      
      console.error('Erro em buyTicket:', error)
      return res.status(500).json({ error: error.message || 'Erro interno' })
    }
  },

  async getOrderStatus(req, res) {
    try {
      const order = await Order.findById(req.params.id)
      if (!order) return res.status(404).json({ error: 'Pedido não encontrado' })
      return res.json({ status: order.status })
    } catch (error) {
      console.error('Erro ao buscar status do pedido:', error)
      return res.status(500).json({ error: 'Erro ao buscar status' })
    }
  },

  async getTickets(req, res) {
    try {
      const tickets = await Ticket.findByRaffle(req.params.raffle_id)
      return res.json(tickets)
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async getAllTickets(req, res) {
    try {
      const tickets = await Ticket.getAll()
      return res.json(tickets)
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async createRaffle(req, res) {
    try {
      const { titulo, descricao, preco_numero, total_numeros, start_at, end_at } = req.body
      if (!titulo) return res.status(400).json({ error: 'Título é obrigatório' })

      const result = await Raffle.create({
        titulo,
        descricao,
        preco_numero:  parseFloat(preco_numero)  || 5.0,
        total_numeros: parseInt(total_numeros)   || 500,
        start_at:      start_at || null,
        end_at:        end_at || null,
        tenant_id:     req.tenant?.id || 1,
      })
      return res.json({ success: true, id: result.lastInsertRowid })
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async deleteTicket(req, res) {
    try {
      const tenantId = req.tenant?.id || 1
      await Ticket.deleteByIdAndTenant(req.params.id, tenantId)
      return res.json({ success: true })
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async getMyTickets(req, res) {
    try {
      if (!req.user || !req.user.cpf) {
        return res.status(401).json({ error: 'Usuário não autenticado' })
      }
      const tickets = await Ticket.findByUserCpf(req.user.cpf)
      return res.json(tickets)
    } catch (error) {
      console.error('Erro ao buscar meus tickets:', error)
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  async drawRaffle(req, res) {
    try {
      const { id } = req.params
      const ip = req.ip || '127.0.0.1'

      const result = await RaffleResult.draw(id, ip)
      return res.json({ success: true, result })
    } catch (error) {
      console.error('Erro no draw:', error)
      return res.status(400).json({ error: error.message || 'Erro interno ao realizar sorteio' })
    }
  },

  async getResult(req, res) {
    try {
      const { id } = req.params
      const result = await RaffleResult.findByRaffleId(id)
      if (!result) return res.status(404).json({ error: 'Nenhum resultado encontrado para este sorteio' })
      return res.json(result)
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno' })
    }
  },

  // PREÇO DINÂMICO
  async getCurrentPrice(req, res) {
    try {
      const data = await PriceRule.getCurrentPrice(req.params.id)
      return res.json(data)
    } catch (error) {
      if (error.message === 'Sorteio não encontrado') return res.status(404).json({ error: error.message })
      return res.status(500).json({ error: 'Erro interno ao consultar preço.' })
    }
  },

  async addPriceRule(req, res) {
    try {
      const { rule_type, price, start_at, end_at, priority } = req.body
      if (!rule_type || !price) return res.status(400).json({ error: 'Regra e Preço obrigatórios' })

      // Captura preço atual antes de criar a nova regra
      const before = await PriceRule.getCurrentPrice(req.params.id).catch(() => null)

      const id = await PriceRule.create({
        raffle_id: req.params.id,
        rule_type,
        price,
        start_at,
        end_at,
        priority,
      })

      // Dispara notificações de queda de preço se o novo preço for menor
      if (before && parseFloat(price) < parseFloat(before.price)) {
        const raffle = await Raffle.findById(req.params.id)
        if (raffle) {
          // Broadcast para todos os opt-in
          NotificationService.notifyPriceDrop(raffle.id, raffle.titulo, price).catch(() => {})
          // Notificação localizada para reservas pendentes de pagamento
          NotificationService.notifyPriceDropLocal(raffle.id, raffle.titulo, price).catch(() => {})
        }
      }

      return res.json({ success: true, id: id.rows?.[0]?.id || id.lastInsertRowid })
    } catch (error) {
      return res.status(500).json({ error: 'Erro interno ao criar regra de preço.' })
    }
  },

  async listPriceRules(req, res) {
    try {
      const rules = await PriceRule.listByRaffle(req.params.id)
      return res.json(rules.rows || rules)
    } catch (error) {
       return res.status(500).json({ error: 'Erro interno ao listar regras.' })
    }
  },

  async getDiscounts(req, res) {
    try {
      const discounts = await RaffleDiscount.listByRaffle(req.params.id)
      return res.json(discounts)
    } catch (error) {
      return res.status(500).json({ error: 'Erro ao listar descontos.' })
    }
  },

  async saveDiscounts(req, res) {
    try {
      const raffleId = parseInt(req.params.id)
      const tiers = req.body.tiers
      if (!Array.isArray(tiers)) return res.status(400).json({ error: 'tiers deve ser um array' })

      const valid = tiers.filter(t =>
        Number.isInteger(parseInt(t.min_qty)) && parseInt(t.min_qty) >= 2 &&
        parseFloat(t.discount_pct) > 0 && parseFloat(t.discount_pct) <= 100
      )

      await RaffleDiscount.deleteByRaffle(raffleId)
      if (valid.length > 0) await RaffleDiscount.bulkInsert(raffleId, valid)

      return res.json({ success: true, saved: valid.length })
    } catch (error) {
      return res.status(500).json({ error: 'Erro ao salvar descontos.' })
    }
  },

  async getFlashPromo(req, res) {
    try {
      const promo = await RaffleFlashPromo.getActive(req.params.id)
      return res.json(promo || null)
    } catch (error) {
      return res.status(500).json({ error: 'Erro ao buscar promoção.' })
    }
  },

  async createFlashPromo(req, res) {
    try {
      const { discount_pct, duration_minutes, label } = req.body
      if (!discount_pct || !duration_minutes) {
        return res.status(400).json({ error: 'discount_pct e duration_minutes são obrigatórios' })
      }
      if (parseFloat(discount_pct) <= 0 || parseFloat(discount_pct) > 100) {
        return res.status(400).json({ error: 'Percentual inválido (1–100)' })
      }
      if (parseInt(duration_minutes) < 1 || parseInt(duration_minutes) > 1440) {
        return res.status(400).json({ error: 'Duração inválida (1–1440 minutos)' })
      }
      const promo = await RaffleFlashPromo.create({
        raffle_id: parseInt(req.params.id),
        discount_pct,
        duration_minutes,
        label
      })
      return res.json({ success: true, promo: promo.rows?.[0] || promo })
    } catch (error) {
      return res.status(500).json({ error: 'Erro ao criar promoção.' })
    }
  },

  async cancelFlashPromo(req, res) {
    try {
      await RaffleFlashPromo.cancel(req.params.promo_id)
      return res.json({ success: true })
    } catch (error) {
      return res.status(500).json({ error: 'Erro ao cancelar promoção.' })
    }
  }
}

module.exports = raffleController
