package usecase

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"apps/backend/internal/module/radar/domain"
)

// MaxManualImportBatch caps one CSV/paste batch so a single request can't force
// an unbounded number of AI judge calls (spec §4.11 P1: 手動匯入不繞過五問判定成本).
const MaxManualImportBatch = 20

// ManualImportItem is one row from a pasted URL or CSV batch import.
type ManualImportItem struct {
	URL      string
	Text     string
	Author   string
	PostedAt int64 // unix ns; <=0 => now (import time)
}

// ManualImportResult reports the outcome of one row so the caller can show a
// per-row status even when some rows in the batch fail or are duplicates.
type ManualImportResult struct {
	URL           string
	OpportunityID string
	Status        string // qualified | rejected | skipped | failed
	IntentBand    string
	IntentScore   int
	Error         string
}

const (
	ImportStatusSkipped = "skipped"
	ImportStatusMerged  = "merged"
	ImportStatusFailed  = "failed"
)

/*
ImportManualOpportunities 讓使用者貼 Threads／Facebook 貼文網址（或 CSV 批次貼上多筆）
建立商機，跑同一套五問判定，來源標 manual_import（spec §4.11 P1）。

不吃每日商機上限：這是使用者主動指定的單筆，不是自動巡的噪音，不該被截斷邏輯擋掉。
同一 owner 下同網址已匯入過 → 略過不重判（跟 sweep 的 dedupe 邏輯一致）。
*/
func (s *Service) ImportManualOpportunities(ctx context.Context, ownerUID int64, items []ManualImportItem) ([]ManualImportResult, error) {
	return s.importManualOpportunities(ctx, ownerUID, items, "", "")
}

// ImportManualProductOpportunities runs the same manual-import path with an
// owned Brand/Product context and attaches ProductMatch evidence.
func (s *Service) ImportManualProductOpportunities(ctx context.Context, ownerUID int64, items []ManualImportItem, brandID, productID string) ([]ManualImportResult, error) {
	brandID, productID = strings.TrimSpace(brandID), strings.TrimSpace(productID)
	if (brandID == "") != (productID == "") {
		return nil, fmt.Errorf("%w: brand_id and product_id must be provided together", domain.ErrValidation)
	}
	return s.importManualOpportunities(ctx, ownerUID, items, brandID, productID)
}

func (s *Service) importManualOpportunities(ctx context.Context, ownerUID int64, items []ManualImportItem, brandID, productID string) ([]ManualImportResult, error) {
	if ownerUID <= 0 {
		return nil, fmt.Errorf("%w: owner required", domain.ErrValidation)
	}
	if len(items) == 0 {
		return nil, fmt.Errorf("%w: at least one item required", domain.ErrValidation)
	}
	if len(items) > MaxManualImportBatch {
		return nil, fmt.Errorf("%w: at most %d rows per import", domain.ErrValidation, MaxManualImportBatch)
	}

	profile, _ := s.Repo.GetServiceProfile(ctx, ownerUID)
	var product *ProductContextSnapshot
	if brandID != "" {
		var err error
		product, err = s.LoadProductContext(ctx, ownerUID, brandID, productID)
		if err != nil {
			return nil, err
		}
	}
	now := domain.NowNano()
	results := make([]ManualImportResult, 0, len(items))

	for _, item := range items {
		rawURL := strings.TrimSpace(item.URL)
		text := strings.TrimSpace(item.Text)
		if rawURL == "" || text == "" {
			results = append(results, ManualImportResult{
				URL: rawURL, Status: ImportStatusFailed, Error: "網址與貼文內文皆必填",
			})
			continue
		}
		if !isImportableURL(rawURL) {
			results = append(results, ManualImportResult{
				URL: rawURL, Status: ImportStatusFailed, Error: "網址格式不正確，需為 http(s) 開頭",
			})
			continue
		}

		if existing, gerr := s.Repo.GetByExternalID(ctx, ownerUID, rawURL); gerr == nil && existing != nil {
			if product != nil && productMatchFor(existing, product.ProductID) == nil {
				postedAt := item.PostedAt
				if postedAt <= 0 {
					postedAt = now
				}
				cand := &domain.CandidatePost{ExternalID: rawURL, Permalink: rawURL, AuthorHandle: item.Author, Text: text, PostedAt: postedAt, MatchedTerm: "manual_import", Classification: classifyCandidate(strings.ToLower(text))}
				match, _, merr := s.scoreProductFit(ctx, ownerUID, product, cand)
				if merr == nil {
					match.MatchedTerms = []string{"manual_import"}
					_, merr = s.Repo.MergeProductMatch(ctx, ownerUID, existing.ID, match)
				}
				if merr != nil {
					results = append(results, ManualImportResult{URL: rawURL, OpportunityID: existing.ID, Status: ImportStatusFailed, Error: "產品匹配合併失敗，請稍後再試"})
				} else {
					results = append(results, ManualImportResult{URL: rawURL, OpportunityID: existing.ID, Status: ImportStatusMerged, IntentBand: existing.IntentBand, IntentScore: existing.IntentScore, Error: "已補上產品匹配，未重建商機"})
				}
				continue
			}
			results = append(results, ManualImportResult{
				URL: rawURL, OpportunityID: existing.ID, Status: ImportStatusSkipped,
				IntentBand: existing.IntentBand, IntentScore: existing.IntentScore,
				Error: "這個網址已經匯入過，略過重複判定",
			})
			continue
		}

		postedAt := item.PostedAt
		if postedAt <= 0 {
			postedAt = now
		}
		author := strings.TrimSpace(item.Author)
		if author == "" {
			author = authorFromURL(rawURL)
		}
		cand := &domain.CandidatePost{
			ExternalID: rawURL, Permalink: rawURL, AuthorHandle: author, Text: text, PostedAt: postedAt,
			MatchedTerm: "manual_import", Classification: classifyCandidate(strings.ToLower(text)),
		}
		var judgeWatch *domain.RadarWatch
		if product != nil {
			judgeWatch = &domain.RadarWatch{ContextMode: domain.WatchContextProduct, BrandID: product.BrandID, ProductID: product.ProductID, ID: "manual-import"}
		}

		res, _, jerr := s.JudgeCandidate(ctx, ownerUID, profile, judgeWatch, cand)
		if jerr != nil || res == nil {
			results = append(results, ManualImportResult{URL: rawURL, Status: ImportStatusFailed, Error: "判定失敗，請稍後再試"})
			continue
		}

		o := &domain.Opportunity{
			ID: domain.NewID(), OwnerUID: ownerUID, Source: domain.OppSourceManualImport,
			ExternalID: rawURL, Permalink: rawURL, AuthorHandle: author, Text: text, PostedAt: postedAt,
			Status: res.Status, IntentScore: res.IntentScore, IntentBand: res.IntentBand,
			Reasons: res.Reasons, RegionDetected: res.RegionDetected, RegionMatch: res.RegionMatch,
			FreshnessHours: res.FreshnessHours, MatchedService: res.MatchedService,
			MatchedTerms: []string{"manual_import"}, RejectReason: res.RejectReason,
		}
		if res.ProductMatch != nil {
			res.ProductMatch.MatchedTerms = []string{"manual_import"}
			o.ProductMatches = []*domain.ProductMatch{res.ProductMatch}
			domain.ApplyPrimaryProduct(o)
		}
		saved, perr := s.Repo.UpsertByExternalID(ctx, o)
		if perr != nil {
			results = append(results, ManualImportResult{URL: rawURL, Status: ImportStatusFailed, Error: "儲存失敗，請稍後再試"})
			continue
		}
		results = append(results, ManualImportResult{
			URL: rawURL, OpportunityID: saved.ID, Status: saved.Status,
			IntentBand: saved.IntentBand, IntentScore: saved.IntentScore,
		})
	}
	return results, nil
}

func isImportableURL(raw string) bool {
	u, err := url.Parse(raw)
	if err != nil {
		return false
	}
	return (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}
