// Package scraper defines the NovelScraper interface and its sub-interfaces.
// Domain types live in internal/domain — this package only defines the scraping
// contract so that novelfire and any future scrapers can be swapped freely.
package scraper

import (
	"context"

	"github.com/libnovel/backend/internal/domain"
)

// CatalogueProvider can enumerate every novel available on a source site.
type CatalogueProvider interface {
	ScrapeCatalogue(ctx context.Context) (<-chan domain.CatalogueEntry, <-chan error)
}

// MetadataProvider can extract structured book metadata from a novel's landing page.
type MetadataProvider interface {
	ScrapeMetadata(ctx context.Context, bookURL string) (domain.BookMeta, error)
}

// ChapterListProvider can enumerate all chapters of a book.
// upTo > 0 stops pagination once at least upTo chapter numbers have been
// collected (early-exit optimisation for range scrapes). upTo == 0 fetches all pages.
type ChapterListProvider interface {
	ScrapeChapterList(ctx context.Context, bookURL string, upTo int) ([]domain.ChapterRef, error)
}

// ChapterTextProvider can extract the readable text from a single chapter page.
type ChapterTextProvider interface {
	ScrapeChapterText(ctx context.Context, ref domain.ChapterRef) (domain.Chapter, error)
}

// RankingProvider can enumerate novels from a ranking page.
type RankingProvider interface {
	// ScrapeRanking pages through up to maxPages ranking pages.
	// maxPages <= 0 means all pages.
	ScrapeRanking(ctx context.Context, maxPages int) (<-chan domain.BookMeta, <-chan error)
}

// NovelScraper is the full interface a concrete novel source must implement.
type NovelScraper interface {
	CatalogueProvider
	MetadataProvider
	ChapterListProvider
	ChapterTextProvider
	RankingProvider

	// SourceName returns the human-readable name of this scraper, e.g. "novelfire.net".
	SourceName() string
}

// Selector describes how to locate an element in an HTML document.
type Selector struct {
	Tag      string
	Class    string
	ID       string
	Attr     string
	Multiple bool
}
