package models

import (
	"log"

	"github.com/sujit-baniya/fiber-boilerplate/app"
	"gorm.io/gorm"
)

type DlocalApi struct {
	gorm.Model
	AccessKeyID        string `gorm:"not null" json:"access_key_id"`     // Access Key ID
	AccessKeySecret    string `gorm:"not null" json:"access_key_secret"` // Access Key Secret
	AccessKeyIDdev     string `gorm:"not null" json:"access_key_id_dev"` // Access Key ID
	AccessKeySecretdev string `gorm:"not null" json:"access_key_secret_dev"`
	IsActive           bool   `gorm:"default:true" json:"is_active"` // Activar o desactivar config
	UrlDev             string `gorm:"type:text"  json:"url_dev"`
	UrlProd            string `gorm:"type:text" json:"url_prod"`
	Modo               string `gorm:"default:'prod'" json:"modo"`
}
type PlanRequest struct {
	Name          string  `json:"name" validate:"required"`
	Description   string  `json:"description" validate:"required"`
	Currency      string  `json:"currency" validate:"required"`
	Amount        float64 `json:"amount" validate:"required"`
	FrequencyType string  `json:"frequency_type" validate:"required"`

	Country         string `json:"country,omitempty"`
	FrequencyValue  int    `json:"frequency_value,omitempty"`
	DayOfMonth      int    `json:"day_of_month,omitempty"`
	NotificationURL string `json:"notification_url,omitempty"`
	SuccessURL      string `json:"success_url,omitempty"`
	BackURL         string `json:"back_url,omitempty"`
	ErrorURL        string `json:"error_url,omitempty"`
}

// TableName asegura que GORM use la tabla 'qrvcard'
func (DlocalApi) TableName() string {
	return "dlocal_api"
}

// GetAllQrVcard obtiene todos los registros de QrVcard con paginación y búsqueda
func GetAllDlocalApi(limit, offset int, search string) ([]DlocalApi, int64, error) {
	var items []DlocalApi
	var total int64
	db := app.Http.Database.DB.Model(&DlocalApi{})

	// Contamos el total de registros
	if err := db.Count(&total).Error; err != nil {
		log.Printf("Error counting DlocalApi: %v", err)
		return nil, 0, err
	}

	// Obtenemos los registros con paginación
	if err := db.Order("id DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
		log.Printf("Error retrieving DlocalApi: %v", err)
		return nil, 0, err
	}

	return items, total, nil
}

// CreateQrVcard crea un nuevo registro de QrVcard en la base de datos
func CreateDlocalApi(DlocalApi *DlocalApi) error {
	if err := app.Http.Database.DB.Create(&DlocalApi).Error; err != nil {
		return err
	}
	return nil
}

// UpdateQrVcard actualiza un registro de QrVcard existente
func UpdateDlocalApi(DlocalApi *DlocalApi) error {
	if err := app.Http.Database.DB.Model(&DlocalApi).Updates(DlocalApi).Error; err != nil {
		return err
	}
	return nil
}

// DeleteQrVcard elimina un registro de QrVcard de la base de datos
func DeleteDlocalApi(DlocalApi *DlocalApi) error {
	if err := app.Http.Database.DB.Delete(&DlocalApi).Error; err != nil {
		return err
	}
	return nil
}

// GetLastActiveDlocalApi obtiene el último registro activo
func GetLastActiveDlocalApi() (*DlocalApi, error) {
	var dlocalConfig DlocalApi
	err := app.Http.Database.DB.
		Where("is_active = ?", true).
		Order("id DESC").
		First(&dlocalConfig).Error
	if err != nil {
		return nil, err
	}
	return &dlocalConfig, nil
}

// ─── DlocalPaymentLog ─────────────────────────────────────────────────────────

// DlocalPaymentLog registra cada pago/notificación de dLocal.
// Cubre webhooks automáticos y registros manuales del backoffice.
type DlocalPaymentLog struct {
	gorm.Model
	// notification_id único; para entradas manuales se genera con prefijo "manual-"
	NotificationID string  `json:"notification_id" gorm:"column:notification_id;uniqueIndex;type:varchar(128);not null"`
	Fuente         string  `json:"fuente"          gorm:"column:fuente;type:varchar(20)"` // "webhook" | "manual"
	Tipo           string  `json:"tipo"            gorm:"column:tipo;type:varchar(50)"`   // PAYMENT, SUBSCRIPTION_CHARGE, …
	Estado         string  `json:"estado"          gorm:"column:estado;type:varchar(30)"` // PAID, PENDING, REJECTED, CANCELLED, EXPIRED
	PaymentID      string  `json:"payment_id"      gorm:"column:payment_id;type:varchar(64)"`
	OrderID        string  `json:"order_id"        gorm:"column:order_id;type:varchar(120)"`
	Referencia     string  `json:"referencia"      gorm:"column:referencia;type:varchar(120)"`
	PayerEmail     string  `json:"payer_email"     gorm:"column:payer_email;type:varchar(255)"`
	Monto          float64 `json:"monto"           gorm:"column:monto"`
	Moneda         string  `json:"moneda"          gorm:"column:moneda;type:varchar(10)"`
	Procesado      bool    `json:"procesado"       gorm:"column:procesado;default:false"`
	Nota           string  `json:"nota"            gorm:"column:nota;type:text"`
	Raw            string  `json:"raw"             gorm:"column:raw;type:text"`
}

func (DlocalPaymentLog) TableName() string { return "dlocal_payment_log" }

// IsDlocalNotificationDuplicate devuelve true si el notification_id ya existe.
func IsDlocalNotificationDuplicate(notificationID string) bool {
	result := app.Http.Database.DB.
		Where("notification_id = ?", notificationID).
		First(&DlocalPaymentLog{})
	return result.Error == nil
}

// SaveDlocalPaymentLog inserta un nuevo registro de pago.
func SaveDlocalPaymentLog(entry DlocalPaymentLog) error {
	return app.Http.Database.DB.Create(&entry).Error
}

// MarkDlocalPaymentProcessed marca el registro como procesado.
func MarkDlocalPaymentProcessed(notificationID string) {
	app.Http.Database.DB.Model(&DlocalPaymentLog{}).
		Where("notification_id = ?", notificationID).
		Update("procesado", true)
}

// GetDlocalPaymentLogs devuelve los últimos N registros ordenados por fecha.
func GetDlocalPaymentLogs(limit int) ([]DlocalPaymentLog, error) {
	var logs []DlocalPaymentLog
	if err := app.Http.Database.DB.Order("id DESC").Limit(limit).Find(&logs).Error; err != nil {
		return nil, err
	}
	return logs, nil
}

// GetDlocalPaymentLogsPaginated devuelve los logs con paginación y filtro por estado.
// El valor especial "APROBADOS" agrupa PAID + AUTHORIZED.
func GetDlocalPaymentLogsPaginated(page, limit int, estado string) ([]DlocalPaymentLog, int64, error) {
	var logs []DlocalPaymentLog
	var total int64
	db := app.Http.Database.DB.Model(&DlocalPaymentLog{})
	switch estado {
	case "", "TODOS":
		// sin filtro
	case "APROBADOS":
		db = db.Where("estado IN ?", []string{"PAID", "AUTHORIZED"})
	default:
		db = db.Where("estado = ?", estado)
	}
	db.Count(&total)
	offset := (page - 1) * limit
	if err := db.Order("id DESC").Limit(limit).Offset(offset).Find(&logs).Error; err != nil {
		return nil, 0, err
	}
	return logs, total, nil
}

// GetDlocalPaymentLogByID carga un registro por su PK.
func GetDlocalPaymentLogByID(id uint, out *DlocalPaymentLog) error {
	return app.Http.Database.DB.First(out, id).Error
}

// UpdateDlocalPaymentLogDatos actualiza email y monto de un log existente.
func UpdateDlocalPaymentLogDatos(id uint, payerEmail string, monto float64) error {
	updates := map[string]interface{}{}
	if payerEmail != "" {
		updates["payer_email"] = payerEmail
	}
	if monto > 0 {
		updates["monto"] = monto
	}
	if len(updates) == 0 {
		return nil
	}
	return app.Http.Database.DB.Model(&DlocalPaymentLog{}).Where("id = ?", id).Updates(updates).Error
}

// GetDlocalPaymentLogsByRef devuelve todos los registros que coinciden con una referencia/order_id.
func GetDlocalPaymentLogsByRef(ref string) ([]DlocalPaymentLog, error) {
	var logs []DlocalPaymentLog
	if err := app.Http.Database.DB.
		Where("referencia = ? OR order_id = ?", ref, ref).
		Order("id DESC").
		Find(&logs).Error; err != nil {
		return nil, err
	}
	return logs, nil
}
