package sitemapgen

import (
	"context"
	"fmt"
	"sync"
	"sync/atomic"
	"time"

	"leadb2b.org/internal/api"
)

var brUFs = []string{
	"AC", "AL", "AP", "AM", "BA", "CE", "DF", "ES", "GO", "MA",
	"MS", "MT", "MG", "PA", "PB", "PR", "PE", "PI", "RJ", "RN",
	"RS", "RO", "RR", "SC", "SP", "SE", "TO",
}

// APIProgress checkpoint por UF durante varredura via API.
type APIProgress struct {
	UF     string
	Cursor string
	Done   bool
}

type APISource struct {
	leads    *api.LeadsService
	workers  int
	pageSize int
}

func NewAPISource(base, key string, workers int) *APISource {
	if workers < 1 {
		workers = 1
	}
	client := api.NewClient(base, key)
	return &APISource{
		leads:    api.NewLeadsService(client),
		workers:  workers,
		pageSize: 50,
	}
}

func (s *APISource) Stream(
	ctx context.Context,
	ufProgress map[string]string,
	completedUFs map[string]bool,
	limit int,
	emit func(Record) error,
	onProgress func(APIProgress),
) error {
	type job struct {
		uf     string
		cursor string
	}
	pending := make([]job, 0, len(brUFs))
	for _, uf := range brUFs {
		if completedUFs != nil && completedUFs[uf] {
			continue
		}
		pending = append(pending, job{uf: uf, cursor: ufProgress[uf]})
	}
	if len(pending) == 0 {
		return nil
	}

	jobs := make(chan job, len(pending))
	errs := make(chan error, s.workers)
	var wg sync.WaitGroup
	var total atomic.Int64

	worker := func() {
		defer wg.Done()
		for j := range jobs {
			if err := s.scanUF(ctx, j.uf, j.cursor, &total, limit, emit, onProgress); err != nil {
				errs <- err
				return
			}
		}
	}

	n := s.workers
	if n > len(pending) {
		n = len(pending)
	}
	wg.Add(n)
	for i := 0; i < n; i++ {
		go worker()
	}
	for _, j := range pending {
		jobs <- j
	}
	close(jobs)
	wg.Wait()
	select {
	case err := <-errs:
		return err
	default:
		return nil
	}
}

func (s *APISource) scanUF(
	ctx context.Context,
	uf, cursor string,
	total *atomic.Int64,
	limit int,
	emit func(Record) error,
	onProgress func(APIProgress),
) error {
	for {
		if err := ctx.Err(); err != nil {
			return err
		}
		params := api.SearchParams{
			UF:                uf,
			SituacaoCadastral: []string{"2"},
			PageSize:          s.pageSize,
			Cursor:            cursor,
		}
		out, err := s.leads.SearchEstabelecimentos(ctx, params)
		if err != nil {
			return fmt.Errorf("uf %s: %w", uf, err)
		}
		for _, item := range out.Items {
			rec := Record{
				CNPJ:          normalizeCNPJ(item.CNPJ),
				RazaoSocial:   item.RazaoSocial,
				MunicipioNome: item.MunicipioNome,
				UF:            item.UF,
			}
			if item.NomeFantasia != nil {
				rec.NomeFantasia = *item.NomeFantasia
			}
			n := total.Add(1)
			if limit > 0 && int(n) > limit {
				return nil
			}
			if err := emit(rec); err != nil {
				return err
			}
		}
		if !out.HasMore || out.NextCursor == nil || *out.NextCursor == "" {
			if onProgress != nil {
				onProgress(APIProgress{UF: uf, Done: true})
			}
			fmt.Printf("UF %s concluída\n", uf)
			return nil
		}
		cursor = *out.NextCursor
		if onProgress != nil {
			onProgress(APIProgress{UF: uf, Cursor: cursor})
		}
		time.Sleep(1100 * time.Millisecond)
	}
}
