import pagarme from 'pagarme'
import 'dotenv/config'

type Gateway = 'mercadopago' | 'pagarme' | 'asaas'

interface SdkConfig {
  gateway: Gateway
  chooseBestGateway?: boolean
  preference?: 'fee' | 'daysToReceive'
  paymentMethod: string
  installmentCount?: number
  publicKey: string
  containerId: string 
  amount: number
  buttonText?: string
  onTokenGenerated: (token: string) => void
  customer: {
    name: string
    email: string
    phone: string
    document: string
    address: {
      number: string
      postalCode: string
    }
  }
}

export class PaymentSdk {
  private gatewayKey = ''
  private baseApiQivoPay = process.env.BASE_API_QIVOPAY

  constructor(private config: SdkConfig) {}

  async init() {
    if (this.config.chooseBestGateway) {
      const { gateway, apiKey } = await this.chooseBestGateway()
      this.config.gateway = gateway
      this.gatewayKey = apiKey

      await this.loadGateways(this.config.gateway)

      return 
    }

   if (!this.config.chooseBestGateway) {
    if (!this.config.gateway) {
      const { gateway, apiKey } = await this.chooseBestGateway()
      this.config.gateway = gateway
      this.gatewayKey = apiKey

      await this.loadGateways(this.config.gateway)

      return
    }

    const { gateway, apiKey } = await this.getGatewayInfo(this.config.gateway)
    this.config.gateway = gateway
    this.gatewayKey = apiKey

    await this.loadGateways(this.config.gateway)
   }
  }

  private async loadGateways(gateway: Gateway) {
    switch(gateway) {
      case 'mercadopago':
        await this.loadMercadoPago()
        this.mountMercadoPagoComponent()
        break
      case 'pagarme':
        await this.loadPagarme()
        this.mountPagarmeForm()
        break
      case 'asaas':
        this.mountAsaasForm()
        break
      default:
        throw new Error('Gateway não suportado')
    }
  }

  private async chooseBestGateway() {
    const { amount, publicKey } = this.config

    const response = await fetch(`${this.baseApiQivoPay}/gateway/best-gateway?amount=${amount}&paymentMethod=${this?.config?.paymentMethod || 'credit_card'}&preference=${this?.config?.preference || 'fee'}&installmentCount=${this?.config?.installmentCount || 1}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${publicKey}`
      }
    })

    if (!response.ok) {
      throw new Error('Erro ao buscar gateway')
    }

    const { data: { gateway, apiKey } } = await response.json()

    return { gateway, apiKey }
  }

  private async getGatewayInfo(gatewayToFind: Gateway) {
    const { publicKey } = this.config

    const response = await fetch(`${this.baseApiQivoPay}/choosed-gateway?gateway=${gatewayToFind}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${publicKey}`
      }
    })

    if (!response.ok) {
      throw new Error('Erro ao buscar gateway')
    }

    const { gateway, apiKey } = await response.json()

    return { gateway, apiKey }
  }

  async loadMercadoPago() {
    return new Promise((resolve, reject) => {
      const scriptId = 'mercado-pago-sdk'
      if (document.getElementById(scriptId)) return resolve(null)

      const script = document.createElement('script')
      script.id = scriptId
      script.src = 'https://sdk.mercadopago.com/js/v2'
      script.onload = () => resolve(null)
      script.onerror = reject
      document.body.appendChild(script)
    })
  }

  mountMercadoPagoComponent() {
    const mp = new window.MercadoPago(this.gatewayKey)

    const form = document.getElementById(this.config.containerId)

    if (!form) {
      throw new Error('Formulário não encontrado')
    }

    form.innerHTML = `
      <form id="mercadopago-form" style="max-width:400px;margin:auto;padding:16px;background:#fff;border-radius:8px;display:flex;flex-direction:column;gap:12px;">
        <input type="text" id="form-name" placeholder="Nome no cartão"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-number" placeholder="Número do cartão"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-expiration" placeholder="MM/YY"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-cvv" placeholder="CVV"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <select id="form-installments"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;">
        ${[...Array(12)].map((_, i) => `<option value="${i + 1}">${i + 1}x</option>`).join('')}
        </select>
        
        <select id="form-issuer"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%; display: none;">
        ${[...Array(12)].map((_, i) => `<option value="${i + 1}">Bandeira ${i + 1}</option>`).join('')}
        </select>
        
        <button type="submit"
        style="padding:12px;background:#2563eb;color:white;border:none;border-radius:6px;font-weight:bold;font-size:16px;cursor:pointer;transition:background 0.2s;">
        ${this.config.buttonText || 'Comprar'}
        </button>
      </form>
    `

    const formFinded = document.getElementById('mercadopago-form')

    if (!formFinded) {
      throw new Error('Formulário não encontrado')
    }

    if (formFinded) {
      const cardForm = mp.cardForm({
        amount: this.config.amount.toString() || '0',
        autoMount: true,
        form: {
          id: `mercadopago-form`,
          cardholderName: { id: 'form-name', placeholder: 'Nome no cartão' },
          cardNumber: { id: 'form-number', placeholder: 'Número do cartão' },
          expirationDate: { id: 'form-expiration', placeholder: 'MM/YY' },
          securityCode: { id: 'form-cvv', placeholder: 'CVV' },
          installments: { id: 'form-installments', placeholder: 'Parcelas' },
          issuer: { id: 'form-issuer', placeholder: 'Bandeira' }
        },
        callbacks: {
          onFormMounted: (error: any) => {
            if (error) return console.warn('Erro ao montar o form:', error)
          },
          onSubmit: async (event: any) => {
            event.preventDefault()
            const { token } = await cardForm.getCardFormData()
            this.config.onTokenGenerated(token)
          }
        }
      })

      requestAnimationFrame(() => {
        cardForm.mount()
      })
    }
  }

  async loadPagarme() {
    if (!pagarme) {
      throw new Error('SDK do Pagar.me não carregado')
    }
  }

  mountPagarmeForm() {
    const form = document.getElementById(this.config.containerId)
    if (!form) {
      throw new Error('Formulário não encontrado')
    }

   form.innerHTML = `
    <form id="pagarme-form" style="max-width:400px;margin:auto;padding:16px;background:#fff;border-radius:8px;display:flex;flex-direction:column;gap:12px;">
      <input type="text" id="card-number" name="number" placeholder="Número do cartão"
      style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
      
      <input type="text" id="card-holder" name="holderName" placeholder="Nome do titular"
      style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
      
      <div style="display:flex;gap:8px;">
      <input type="text" id="card-exp-month" name="expMonth" placeholder="MM"
          style="flex:1;padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;" />
          
      <input type="text" id="card-exp-year" name="expYear" placeholder="YYYY"
          style="flex:1;padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;" />
      </div>
      
      <input type="text" id="card-cvv" name="cvv" placeholder="CVV"
      style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
      
      <select id="form-installments" style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;">
      ${[...Array(12)].map((_, i) => `<option value="${i + 1}">${i + 1}x</option>`).join('')}
      </select>
      
      <select id="form-issuer" style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%; display: none;">
      ${[...Array(12)].map((_, i) => `<option value="${i + 1}">Bandeira ${i + 1}</option>`).join('')}
      </select>
      
      <button type="submit"
      style="padding:12px;background:#2563eb;color:white;border:none;border-radius:6px;font-weight:bold;font-size:16px;cursor:pointer;transition:background 0.2s;">
      ${this.config.buttonText || 'Comprar'}
      </button>
    </form>
  `

    const getValue = (name: string) =>
      (form.querySelector(`input[name="${name}"]`) as HTMLInputElement)?.value?.trim() || ''

    form.addEventListener('submit', async (e) => {
      e.preventDefault()

      const cardData = {
        number: getValue('number'),
        holderName: getValue('holderName'),
        expMonth: getValue('expMonth'),
        expYear: getValue('expYear'),
        cvv: getValue('cvv'),
      }

      const client = await pagarme.client.connect({ api_key: this.gatewayKey })

      const cardHash = await client.security.createCardHash({
        card_number: cardData.number,
        card_holder_name: cardData.holderName,
        card_expiration_date: `${cardData.expMonth}${cardData.expYear.slice(2)}`, // MMYY
        card_cvv: cardData.cvv
      })

      this.config.onTokenGenerated(cardHash)
    })
  }

  mountAsaasForm() {
    const form = document.getElementById(this.config.containerId)
    if (!form) {
      throw new Error('Formulário não encontrado')
    }

    form.innerHTML = `
      <form id="asaas-form" style="max-width:400px;margin:auto;padding:16px;background:#fff;border-radius:8px;display:flex;flex-direction:column;gap:12px;">
        <input type="text" id="form-name" placeholder="Nome no cartão"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-number" placeholder="Número do cartão"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-expiration" placeholder="MM/YY"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <input type="text" id="form-cvv" placeholder="CVV"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;" />
        
        <select id="form-installments"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%;">
        ${[...Array(12)].map((_, i) => `<option value="${i + 1}">${i + 1}x</option>`).join('')}
        </select>
        
        <select id="form-issuer"
        style="padding:10px;border:1px solid #ccc;border-radius:6px;font-size:14px;width:100%; display: none;">
        ${[...Array(12)].map((_, i) => `<option value="${i + 1}">Bandeira ${i + 1}</option>`).join('')}
        </select>
        
        <button type="submit"
        style="padding:12px;background:#2563eb;color:white;border:none;border-radius:6px;font-weight:bold;font-size:16px;cursor:pointer;transition:background 0.2s;">
        ${this.config.buttonText || 'Comprar'}
        </button>
      </form>
    `

    const getValue = (name: string) =>
      (form.querySelector(`input[name="${name}"]`) as HTMLInputElement)?.value?.trim() || ''

    form.addEventListener('submit', async (e) => {
      e.preventDefault()
      const apiKey = this.gatewayKey
      const asaasBaseUrl = 'https://api.asaas.com/v3'

      const getCustomer: any = await fetch(`${asaasBaseUrl}/customers?email=${this.config.customer.email}`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`
        }
      })

      let createdCustomer: any = null
      if (!getCustomer.data) {
        createdCustomer = await fetch(`${asaasBaseUrl}/customers`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${apiKey}`
          },
          body: JSON.stringify({
            email: this.config.customer.email,
            name: this.config.customer.name,
            phone: this.config.customer.phone,
            cpfCnpj: this.config.customer.document
          })
        })
      }
      

      const cardData = {
        customer: createdCustomer.data.id,
        number: getValue('number'),
        holderName: getValue('holderName'),
        expMonth: getValue('expMonth'),
        expYear: getValue('expYear'),
        cvv: getValue('cvv'),
        creditCard: {
          holderName: getValue('holderName'),
          number: getValue('number'),
          expiryMonth: getValue('expMonth'),
          expiryYear: getValue('expYear'),
          cvv: getValue('cvv')
        },
        creditCardHolderInfo: {
          name: getValue('holderName'),
          email: getValue('email'),
          cpfCnpj: getValue('document'),
          phone: getValue('phone'),
          postalCode: this.config.customer.address.postalCode,
          addressNumber: this.config.customer.address.number,
        }
      }

      fetch(`${asaasBaseUrl}/creditCard/tokenizeCreditCard`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.gatewayKey}`
        },
        body: JSON.stringify(cardData)
      })
        .then(res => res.json())
        .then(data => {
          this.config.onTokenGenerated(data.token)
        })
    })
  }
  
  destroy() {
    const container = document.getElementById(this.config.containerId)
    if (container) container.innerHTML = ''
  }
}