package scraper

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	basescraper "github.com/yourorg/devour/internal/scraper"
)

type SourceType = basescraper.SourceType

type Source = basescraper.Source

type Document = basescraper.Document

type Config = basescraper.Config

func generateDocID(urlStr string) string {
	hash := sha256.Sum256([]byte(urlStr))
	return hex.EncodeToString(hash[:12])
}

func fetchExternalPage(ctx context.Context, client *http.Client, userAgent, targetURL string) (string, error) {
	req, err := http.NewRequestWithContext(ctx, "GET", targetURL, nil)
	if err != nil {
		return "", err
	}

	req.Header.Set("User-Agent", userAgent)

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		snippet, readErr := readErrorSnippet(resp.Body)
		if readErr != nil {
			return "", fmt.Errorf("GET %s returned HTTP %d and body read failed: %w", summarizeURL(targetURL), resp.StatusCode, readErr)
		}
		return "", fmt.Errorf("GET %s returned HTTP %d: %s", summarizeURL(targetURL), resp.StatusCode, snippet)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(body), nil
}

func readErrorSnippet(body io.Reader) (string, error) {
	const maxErrorBodyBytes = 512
	data, err := io.ReadAll(io.LimitReader(body, maxErrorBodyBytes))
	if err != nil {
		return "", err
	}

	msg := strings.TrimSpace(string(data))
	if msg == "" {
		return "<empty body>", nil
	}

	return msg, nil
}

func summarizeURL(rawURL string) string {
	parsedURL, err := url.Parse(rawURL)
	if err != nil || parsedURL.Host == "" {
		return rawURL
	}

	path := parsedURL.EscapedPath()
	if path == "" {
		path = "/"
	}

	return parsedURL.Host + path
}
