package sync

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"strings"
	"time"
)

// SeenPartnumber represents an unresolved vendor partnumber to report.
type SeenPartnumber struct {
	Partnumber    string
	Description   string
	Ignored       bool
	LotSuggestion []LotSuggestionEntry // optional; set when user manually mapped PN → LOT in UI
}

// LotSuggestionEntry is one suggested LOT mapping for a vendor partnumber.
// JSON shape mirrors qt_partnumber_book_items.lots_json: {"lot_name", "qty"}.
type LotSuggestionEntry struct {
	LotName string `json:"lot_name"`
	Qty     int    `json:"qty"`
}

// PushPartnumberSeen inserts unresolved vendor partnumbers into qt_vendor_partnumber_seen on MariaDB.
// When LotSuggestion is provided the column is updated too; if the column does not exist yet
// (migration pending) the write is retried without it and a warning is logged — the app never panics.
func (s *Service) PushPartnumberSeen(items []SeenPartnumber) error {
	if len(items) == 0 {
		return nil
	}

	mariaDB, err := s.getDB()
	if err != nil {
		return fmt.Errorf("database not available: %w", err)
	}

	now := time.Now().UTC()
	for _, item := range items {
		if item.Partnumber == "" {
			continue
		}

		if len(item.LotSuggestion) > 0 {
			suggJSON, marshalErr := json.Marshal(item.LotSuggestion)
			if marshalErr != nil {
				slog.Error("partnumber_seen: failed to marshal lot_suggestion, skipping suggestion",
					"partnumber", item.Partnumber, "error", marshalErr)
				suggJSON = nil
			}

			if suggJSON != nil {
				err = mariaDB.Exec(`
					INSERT INTO qt_vendor_partnumber_seen
						(source_type, vendor, partnumber, description, is_ignored, last_seen_at, lot_suggestion)
					VALUES
						('manual', '', ?, ?, ?, ?, ?)
					ON DUPLICATE KEY UPDATE
						lot_suggestion = VALUES(lot_suggestion),
						last_seen_at   = NOW(3)
				`, item.Partnumber, item.Description, item.Ignored, now, string(suggJSON)).Error

				if err == nil {
					continue
				}

				// Column not yet migrated — fall through to insert without lot_suggestion.
				if !isUnknownColumnError(err) {
					slog.Error("partnumber_seen: failed to upsert with lot_suggestion",
						"partnumber", item.Partnumber, "error", err)
					continue
				}
				slog.Warn("partnumber_seen: lot_suggestion column missing (migration pending), inserting without it",
					"partnumber", item.Partnumber)
			}
		}

		// Insert without lot_suggestion (baseline behaviour or fallback).
		err = mariaDB.Exec(`
			INSERT INTO qt_vendor_partnumber_seen
				(source_type, vendor, partnumber, description, is_ignored, last_seen_at)
			VALUES
				('manual', '', ?, ?, ?, ?)
			ON DUPLICATE KEY UPDATE
				partnumber = partnumber
		`, item.Partnumber, item.Description, item.Ignored, now).Error
		if err != nil {
			slog.Error("failed to insert partnumber_seen", "partnumber", item.Partnumber, "error", err)
		}
	}

	slog.Info("partnumber_seen pushed to server", "count", len(items))
	return nil
}

// isUnknownColumnError returns true when MariaDB reports that a column does not exist.
func isUnknownColumnError(err error) bool {
	if err == nil {
		return false
	}
	msg := strings.ToLower(err.Error())
	return strings.Contains(msg, "unknown column") || strings.Contains(msg, "1054")
}
