package routes

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"html"
	"log"
	"net/http"
	"strings"
	"time"

	"bssapp-backend/auth"
	"bssapp-backend/internal/mailer"

	"github.com/lib/pq"
)

type orderPriceListExportNotifyRequest struct {
	Format         string   `json:"format"`
	RowCount       int      `json:"row_count"`
	PriceFields    []string `json:"price_fields"`
	ProductCodes   []string `json:"product_codes"`
	CampaignLabels []string `json:"campaign_labels"`
	FirstGroups    []string `json:"first_groups"`
	UrunIlkGrubu   string   `json:"urun_ilk_grubu"`
	UrunAnaGrubu   string   `json:"urun_ana_grubu"`
}

func NotifyOrderPriceListExportHandler(pg *sql.DB, ml *mailer.GraphMailer) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		claims, ok := auth.GetClaimsFromContext(r.Context())
		if !ok || claims == nil {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}
		if ml == nil {
			http.Error(w, "mailer unavailable", http.StatusServiceUnavailable)
			return
		}
		if err := ensureFirstGroupMailMappingTables(pg); err != nil {
			http.Error(w, "mapping table bootstrap error", http.StatusInternalServerError)
			return
		}

		var req orderPriceListExportNotifyRequest
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			http.Error(w, "invalid payload", http.StatusBadRequest)
			return
		}

		groups := normalizeExportNotifyList(req.FirstGroups, 100)
		if len(groups) == 0 {
			groups = normalizeExportNotifyList([]string{req.UrunIlkGrubu}, 100)
		}
		recipients, err := loadOrderPriceListRecipients(pg, groups)
		if err != nil {
			http.Error(w, "recipient lookup error", http.StatusInternalServerError)
			return
		}
		if len(recipients) == 0 {
			log.Printf("[order-price-list-export-notify] no recipients groups=%v", groups)
			w.Header().Set("Content-Type", "application/json; charset=utf-8")
			_ = json.NewEncoder(w).Encode(map[string]any{"ok": true, "sent": false, "reason": "no_recipients"})
			return
		}

		actor := strings.TrimSpace(claims.Username)
		if actor == "" {
			actor = fmt.Sprintf("user-%d", claims.ID)
		}
		format := strings.ToUpper(strings.TrimSpace(req.Format))
		if format == "" {
			format = "CIKTI"
		}
		now := time.Now()
		htmlBody := buildOrderPriceListExportNotifyHTML(req, actor, format, groups, now)

		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
		defer cancel()
		if err := ml.Send(ctx, mailer.Message{
			To:       recipients,
			Subject:  fmt.Sprintf("Fiyat Listesi Ciktisi Alindi | %s | %s", actor, now.Format("02.01.2006 15:04")),
			BodyHTML: htmlBody,
		}); err != nil {
			log.Printf("[order-price-list-export-notify] send failed user=%s format=%s err=%v", actor, format, err)
			http.Error(w, "mail send error", http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		_ = json.NewEncoder(w).Encode(map[string]any{"ok": true, "sent": true, "recipient_count": len(recipients)})
	}
}

func loadOrderPriceListRecipients(pg *sql.DB, groups []string) ([]string, error) {
	groups = normalizeExportNotifyList(groups, 100)
	if len(groups) == 0 {
		return nil, nil
	}
	rows, err := pg.Query(`
SELECT DISTINCT TRIM(m.email) AS email
FROM mk_order_price_list_first_group_mail f
JOIN mk_mail m
  ON m.id = f.mail_id
WHERE m.is_active = true
  AND COALESCE(TRIM(m.email), '') <> ''
  AND UPPER(TRIM(f.urun_ilk_grubu)) = ANY($1)
ORDER BY email
`, pq.Array(upperExportNotifyList(groups)))
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	out := make([]string, 0, 16)
	for rows.Next() {
		var email string
		if err := rows.Scan(&email); err != nil {
			return nil, err
		}
		email = strings.TrimSpace(email)
		if email != "" {
			out = append(out, email)
		}
	}
	return out, rows.Err()
}

func buildOrderPriceListExportNotifyHTML(req orderPriceListExportNotifyRequest, actor string, format string, groups []string, now time.Time) string {
	return fmt.Sprintf(`
<h3>Fiyat Listesi Ciktisi Alindi</h3>
<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;border:1px solid #ddd">
  <tr><td><b>Islem Yapan</b></td><td>%s</td></tr>
  <tr><td><b>Cikti Tipi</b></td><td>%s</td></tr>
  <tr><td><b>Tarih</b></td><td>%s</td></tr>
  <tr><td><b>Satir Sayisi</b></td><td>%d</td></tr>
  <tr><td><b>Secili Fiyat Gruplari</b></td><td>%s</td></tr>
  <tr><td><b>Urun Ilk Gruplari</b></td><td>%s</td></tr>
  <tr><td><b>Urun Ana Grubu</b></td><td>%s</td></tr>
  <tr><td><b>Urun Kodlari</b></td><td>%s</td></tr>
  <tr><td><b>Kampanya Filtreleri</b></td><td>%s</td></tr>
</table>`,
		html.EscapeString(actor),
		html.EscapeString(format),
		html.EscapeString(now.Format("02.01.2006 15:04")),
		req.RowCount,
		html.EscapeString(strings.Join(normalizeExportNotifyList(req.PriceFields, 24), ", ")),
		html.EscapeString(strings.Join(groups, ", ")),
		html.EscapeString(orderNotifyDash(req.UrunAnaGrubu)),
		html.EscapeString(strings.Join(normalizeExportNotifyList(req.ProductCodes, 50), ", ")),
		html.EscapeString(strings.Join(normalizeExportNotifyList(req.CampaignLabels, 20), ", ")),
	)
}

func normalizeExportNotifyList(in []string, limit int) []string {
	out := make([]string, 0, len(in))
	seen := make(map[string]struct{}, len(in))
	for _, raw := range in {
		v := strings.TrimSpace(raw)
		if v == "" || v == "-" {
			continue
		}
		key := strings.ToUpper(v)
		if _, ok := seen[key]; ok {
			continue
		}
		seen[key] = struct{}{}
		out = append(out, v)
		if limit > 0 && len(out) >= limit {
			break
		}
	}
	return out
}

func upperExportNotifyList(in []string) []string {
	out := make([]string, 0, len(in))
	for _, v := range normalizeExportNotifyList(in, 0) {
		out = append(out, strings.ToUpper(strings.TrimSpace(v)))
	}
	return out
}

func orderNotifyDash(v string) string {
	v = strings.TrimSpace(v)
	if v == "" {
		return "-"
	}
	return v
}
