package handlers

import (
	"database/sql"
	"encoding/json"
	"io"
	"log"
	"net/http"

	"webhook-service/config"
	"webhook-service/models"
	"webhook-service/worker"
)

type WebhookHandler struct {
	config *config.Config
	db     *sql.DB
	worker *worker.Pool
}

func NewWebhookHandler(cfg *config.Config, db *sql.DB, workerPool *worker.Pool) *WebhookHandler {
	return &WebhookHandler{
		config: cfg,
		db:     db,
		worker: workerPool,
	}
}

func (h *WebhookHandler) HandleWebhook(w http.ResponseWriter, r *http.Request) {
	log.Printf("📥 [Webhook] Incoming %s %s Content-Length:%v", r.Method, r.URL.Path, r.ContentLength)

	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	body, err := io.ReadAll(r.Body)
	if err != nil {
		log.Printf("❌ [Webhook] Read body error: %v", err)
		http.Error(w, "Read error", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()

	var payloads []models.WebhookPayload
	if err := json.Unmarshal(body, &payloads); err != nil {
		// Accurate kadang mengirim single object, bukan array
		var single models.WebhookPayload
		if err2 := json.Unmarshal(body, &single); err2 != nil {
			log.Printf("❌ [Webhook] Invalid JSON (array and object): %v", err)
			http.Error(w, "Invalid JSON", http.StatusBadRequest)
			return
		}
		payloads = []models.WebhookPayload{single}
		log.Printf("📦 [Webhook] Parsed as single object, type=%s", single.Type)
	} else {
		// Batch detected - log semua tipe dalam batch
		types := make([]string, len(payloads))
		for i, p := range payloads {
			types[i] = p.Type
		}
		log.Printf("📦 [Webhook] Batch detected: %d payload(s) - types: %v", len(payloads), types)
	}

	if len(payloads) == 0 {
		http.Error(w, "Empty data", http.StatusBadRequest)
		return
	}

	// Support batch: proses semua payload dalam array
	var queueIDs []int64
	for i, payload := range payloads {
		// Idempotency check: jika UUID ada dan sudah pernah diproses, skip
		if payload.UUID != "" {
			var existingID int64
			err := h.db.QueryRow(`
				SELECT id FROM webhook_queue WHERE uuid = ? LIMIT 1
			`, payload.UUID).Scan(&existingID)

			if err == nil {
				// UUID sudah ada - duplicate webhook, skip
				log.Printf("⚠️ [Webhook] Duplicate detected (UUID: %s), skipping payload %d/%d", payload.UUID, i+1, len(payloads))
				queueIDs = append(queueIDs, existingID) // Return existing ID untuk response
				continue
			}
			// err != nil berarti UUID belum ada, lanjut insert
		}

		// Simpan setiap payload ke SQLite queue
		// Untuk batch, kita perlu extract payload individual dari body
		// Karena body adalah array, kita perlu marshal ulang setiap item
		payloadJSON, err := json.Marshal(payload)
		if err != nil {
			log.Printf("⚠️ [Webhook] Failed to marshal payload %d: %v", i, err)
			continue
		}

		result, err := h.db.Exec(`
			INSERT INTO webhook_queue (type, database_id, uuid, payload, status)
			VALUES (?, ?, ?, ?, 'pending')
		`, payload.Type, payload.DatabaseID, payload.UUID, string(payloadJSON))

		if err != nil {
			// Check jika error karena duplicate UUID (race condition)
			if payload.UUID != "" {
				var existingID int64
				err2 := h.db.QueryRow(`
					SELECT id FROM webhook_queue WHERE uuid = ? LIMIT 1
				`, payload.UUID).Scan(&existingID)
				if err2 == nil {
					log.Printf("⚠️ [Webhook] Duplicate detected during insert (UUID: %s), using existing queue_id=%d", payload.UUID, existingID)
					queueIDs = append(queueIDs, existingID)
					continue
				}
			}
			log.Printf("❌ [Webhook] Queue Error for payload %d: %v", i, err)
			continue
		}

		queueID, _ := result.LastInsertId()
		h.worker.Submit(queueID)
		queueIDs = append(queueIDs, queueID)
		log.Printf("  → [Webhook] Queued payload %d/%d: type=%s, uuid=%s, queue_id=%d", i+1, len(payloads), payload.Type, payload.UUID, queueID)
	}

	if len(queueIDs) == 0 {
		http.Error(w, "Failed to queue any payload", http.StatusInternalServerError)
		return
	}

	log.Printf("✅ [Webhook] Successfully queued %d payload(s) - queue IDs: %v", len(queueIDs), queueIDs)

	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]interface{}{
		"status": "success",
		"count":  len(queueIDs),
		"ids":    queueIDs,
	})
}

func (h *WebhookHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	w.Write([]byte("OK"))
}
