package models

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

// SaasApiConfig almacena la configuración del endpoint externo al que se notifica
// cuando un pago es confirmado para un producto SaaS.
// La vinculación es: Contrato → Servicios (m2m) → servicio_id ↔ SaasProducto.ServicioID → SaasApiConfig.SaasID
type SaasApiConfig struct {
	gorm.Model
	SaasID       uint         `json:"saas_id"          gorm:"column:saas_id;not null;index"`
	SaasProducto SaasProducto `json:"saas_producto"    gorm:"foreignKey:SaasID"`
	Nombre       string       `json:"nombre"           gorm:"column:nombre;not null"` // etiqueta amigable
	// Pasarela que dispara este callback: dlocal | bold | ambas (default)
	Pasarela     string `json:"pasarela"         gorm:"column:pasarela;default:'ambas'"`
	EndpointURL  string `json:"endpoint_url"     gorm:"column:endpoint_url;type:text;not null"`
	Metodo       string `json:"metodo"           gorm:"column:metodo;default:'POST'"`   // POST|PUT|GET
	ApiKeyHeader string `json:"api_key_header"   gorm:"column:api_key_header"`          // ej: "X-API-Key"
	ApiKeyValue  string `json:"api_key_value"    gorm:"column:api_key_value;type:text"` // valor secreto
	// PayloadTemplate es un JSON con marcadores que se reemplazarán antes de enviar.
	// Variables disponibles: {{.ContratoID}} {{.Referencia}} {{.Email}} {{.Monto}} {{.Moneda}} {{.SaasID}} {{.SaasSlug}} {{.Fuente}} {{.WebhookToken}}
	PayloadTemplate string `json:"payload_template" gorm:"column:payload_template;type:text"`
	TimeoutSeg      int    `json:"timeout_seg"      gorm:"column:timeout_seg;default:10"`
	Activo          bool   `json:"activo"           gorm:"column:activo;default:true"`
	// WebhookToken es un token único por integración que identifica las llamadas entrantes
	// desde el SaaS externo vía POST /webhooks/saas-in/{token}
	WebhookToken string `json:"webhook_token" gorm:"column:webhook_token;uniqueIndex;size:64"`
}

func (SaasApiConfig) TableName() string { return "saas_api_configs" }

// ─── SaasWebhookInLog ─────────────────────────────────────────────────────────

// SaasWebhookInLog registra cada llamada entrante desde un SaaS externo
// identificado por su WebhookToken único.
type SaasWebhookInLog struct {
	gorm.Model
	SaasApiConfigID uint   `json:"saas_api_config_id" gorm:"column:saas_api_config_id;index"`
	Token           string `json:"token"              gorm:"column:token;size:64;index"`
	Metodo          string `json:"metodo"             gorm:"column:metodo;size:10"`
	IP              string `json:"ip"                 gorm:"column:ip;size:64"`
	Body            string `json:"body"               gorm:"column:body;type:text"`
	Headers         string `json:"headers"            gorm:"column:headers;type:text"`
}

func (SaasWebhookInLog) TableName() string { return "saas_webhook_in_logs" }

// ─── SaasDispatchLog ──────────────────────────────────────────────────────────

// SaasDispatchLog registra cada intento de notificación a un SaaS externo.
type SaasDispatchLog struct {
	gorm.Model
	SaasApiConfigID uint          `json:"saas_api_config_id" gorm:"column:saas_api_config_id;index"`
	SaasApiConfig   SaasApiConfig `json:"saas_api_config"    gorm:"foreignKey:SaasApiConfigID"`
	ContratoID      uint          `json:"contrato_id"        gorm:"column:contrato_id;index"`
	Referencia      string        `json:"referencia"         gorm:"column:referencia"`
	PayerEmail      string        `json:"payer_email"        gorm:"column:payer_email"`
	Fuente          string        `json:"fuente"             gorm:"column:fuente"` // dlocal | bold | manual
	HttpStatus      int           `json:"http_status"        gorm:"column:http_status"`
	Respuesta       string        `json:"respuesta"          gorm:"column:respuesta;type:text"`
	ErrorMsg        string        `json:"error_msg"          gorm:"column:error_msg;type:text"`
	Estado          string        `json:"estado"             gorm:"column:estado"` // success | failed
	Intentos        int           `json:"intentos"           gorm:"column:intentos;default:1"`
}

func (SaasDispatchLog) TableName() string { return "saas_dispatch_logs" }

// ─── Queries SaasApiConfig ────────────────────────────────────────────────────

func GetAllSaasApiConfigs(limit, offset int) ([]SaasApiConfig, int64, error) {
	var items []SaasApiConfig
	var total int64
	db := app.Http.Database.DB.Model(&SaasApiConfig{}).Preload("SaasProducto")
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	if err := db.Order("created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
		return nil, 0, err
	}
	return items, total, nil
}

func GetSaasApiConfigByID(id uint) (*SaasApiConfig, error) {
	var item SaasApiConfig
	if err := app.Http.Database.DB.Preload("SaasProducto").First(&item, id).Error; err != nil {
		return nil, err
	}
	return &item, nil
}

// GetSaasApiConfigsBySaasIDs devuelve configuraciones activas para los saas_ids dados,
// opcionalmente filtradas por pasarela ("dlocal", "bold" o "" para todas).
func GetSaasApiConfigsBySaasIDs(saasIDs []uint, pasarela string) ([]SaasApiConfig, error) {
	if len(saasIDs) == 0 {
		return nil, nil
	}
	db := app.Http.Database.DB.
		Preload("SaasProducto").
		Where("saas_id IN ? AND activo = ?", saasIDs, true)
	if pasarela != "" {
		db = db.Where("pasarela = ? OR pasarela = 'ambas'", pasarela)
	}
	var items []SaasApiConfig
	if err := db.Find(&items).Error; err != nil {
		return nil, err
	}
	return items, nil
}

func CreateSaasApiConfig(item *SaasApiConfig) error {
	return app.Http.Database.DB.Create(item).Error
}

func UpdateSaasApiConfig(item *SaasApiConfig) error {
	return app.Http.Database.DB.Save(item).Error
}

func DeleteSaasApiConfig(id uint) error {
	return app.Http.Database.DB.Delete(&SaasApiConfig{}, id).Error
}

// GetSaasApiConfigByWebhookToken busca una integración por su token de webhook entrante.
func GetSaasApiConfigByWebhookToken(token string) (*SaasApiConfig, error) {
	var item SaasApiConfig
	if err := app.Http.Database.DB.Preload("SaasProducto").
		Where("webhook_token = ? AND activo = true", token).
		First(&item).Error; err != nil {
		return nil, err
	}
	return &item, nil
}

// SaveSaasWebhookInLog persiste un log de webhook entrante.
func SaveSaasWebhookInLog(entry *SaasWebhookInLog) error {
	return app.Http.Database.DB.Create(entry).Error
}

// ─── Queries SaasDispatchLog ──────────────────────────────────────────────────

func SaveSaasDispatchLog(entry *SaasDispatchLog) error {
	return app.Http.Database.DB.Create(entry).Error
}

func GetSaasDispatchLogs(limit, offset int) ([]SaasDispatchLog, int64, error) {
	var items []SaasDispatchLog
	var total int64
	db := app.Http.Database.DB.Model(&SaasDispatchLog{}).Preload("SaasApiConfig")
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	if err := db.Order("created_at DESC").Limit(limit).Offset(offset).Find(&items).Error; err != nil {
		return nil, 0, err
	}
	return items, total, nil
}

// GetDispatchLogsByContratoID devuelve los pagos/dispatches de un contrato específico
func GetDispatchLogsByContratoID(contratoID uint) ([]SaasDispatchLog, error) {
	var items []SaasDispatchLog
	if err := app.Http.Database.DB.
		Where("contrato_id = ?", contratoID).
		Order("created_at DESC").
		Limit(50).
		Find(&items).Error; err != nil {
		return nil, err
	}
	return items, nil
}
