// Package jellyfin — минимальный клиент Jellyfin для пересканирования
// медиатеки после успешной раскладки. Единственная задача: дёрнуть скан
// всех библиотек (POST /Library/Refresh), чтобы новые хардлинки быстрее
// появились в проигрывателе. В духе сервиса — без зоопарка вызовов.
package jellyfin

import (
	"context"
	"fmt"
	"io"
	"log/slog"
	"net/http"
	"net/url"
	"strings"
	"time"

	"git.vakhrushev.me/av/jellybit/internal/logctx"
	"git.vakhrushev.me/av/jellybit/internal/logging"
)

const defaultTimeout = 10 * time.Second

// Config — подключение к Jellyfin.
type Config struct {
	URL     string
	APIKey  string
	Proxy   string // опц. HTTP-прокси
	Timeout time.Duration
}

// Client — клиент Jellyfin API.
type Client struct {
	base   string
	apiKey string
	hc     *http.Client
	log    *slog.Logger
}

// New собирает клиент с опц. прокси. logger nil → slog.Default().
func New(cfg Config, logger *slog.Logger) (*Client, error) {
	base, err := url.Parse(strings.TrimRight(cfg.URL, "/"))
	if err != nil {
		return nil, fmt.Errorf("jellyfin: parse url %q: %w", cfg.URL, err)
	}
	timeout := cfg.Timeout
	if timeout <= 0 {
		timeout = defaultTimeout
	}
	transport := http.DefaultTransport
	if cfg.Proxy != "" {
		pu, perr := url.Parse(cfg.Proxy)
		if perr != nil {
			return nil, fmt.Errorf("jellyfin: parse proxy %q: %w", cfg.Proxy, perr)
		}
		// Клонируем дефолтный транспорт (dial/TLS-таймауты, keep-alive), а не
		// собираем голый — как в metadata-клиенте.
		t := http.DefaultTransport.(*http.Transport).Clone()
		t.Proxy = http.ProxyURL(pu)
		transport = t
	}
	if logger == nil {
		logger = slog.Default()
	}
	return &Client{
		base:   base.String(),
		apiKey: cfg.APIKey,
		hc:     &http.Client{Timeout: timeout, Transport: transport},
		log:    logger,
	}, nil
}

// RefreshLibraries запускает скан всех библиотек Jellyfin
// (POST /Library/Refresh). Скан инкрементальный — полный дёшев, поэтому
// точечный скан конкретной папки не делаем (сложнее, не в духе сервиса).
// Ответ при успехе — 204 No Content.
func (c *Client) RefreshLibraries(ctx context.Context) error {
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.base+"/Library/Refresh", nil)
	if err != nil {
		return fmt.Errorf("jellyfin: build request: %w", err)
	}
	req.Header.Set("X-Emby-Token", c.apiKey)

	log := logctx.FromOr(ctx, c.log)
	call := logging.StartCall(logging.ServiceJellyfin, "library/refresh")
	resp, err := c.hc.Do(req)
	if err != nil {
		call.Failure(log, err)
		return fmt.Errorf("jellyfin: refresh: %w", err)
	}
	defer func() { _ = resp.Body.Close() }()
	call.Status = resp.StatusCode
	body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<10))
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		err := fmt.Errorf("jellyfin: refresh: status %d body %q",
			resp.StatusCode, strings.TrimSpace(string(body)))
		call.Failure(log, err)
		return err
	}
	call.Success(log)
	return nil
}
