package main

import (
	"context"
	"fmt"

	"gitea.d-ma.be/mathias/tapir/internal/adapters/llm"
	"gitea.d-ma.be/mathias/tapir/internal/adapters/secrets"
	"gitea.d-ma.be/mathias/tapir/internal/adapters/store"
	"gitea.d-ma.be/mathias/tapir/internal/adapters/summarizer"
	"gitea.d-ma.be/mathias/tapir/internal/adapters/youtube"
	"gitea.d-ma.be/mathias/tapir/internal/config"
	"gitea.d-ma.be/mathias/tapir/internal/domain"
	"gitea.d-ma.be/mathias/tapir/internal/usecase"
)

// buildProcessor wires the summarization engine — YouTube source (captions-first),
// AI-router summarizer, store sink — shared by `tapir run` and the web
// "Summarize now" path so the wiring lives in one place. It returns (nil, nil) —
// not an error — when the config cannot support live summarization (no gateway
// URL, no YouTube client credentials, or no secrets file). That nil is the
// queue-only fallback: the web UI keeps working (the button just queues) and
// `tapir run` reports the gap via its own ValidateForRun. Missing engine config
// is never an error here.
func buildProcessor(cfg config.Config, st *store.Store) (*usecase.Engine, error) {
	if cfg.GatewayURL == "" || cfg.YTClientID == "" || cfg.YTClientSecret == "" || cfg.SecretsFile == "" {
		return nil, nil
	}

	secretStore := secrets.NewFileStore(cfg.SecretsFile)
	src := youtube.New(youtube.Config{
		ClientID:           cfg.YTClientID,
		ClientSecret:       cfg.YTClientSecret,
		TokenSecretRef:     cfg.YTTokenRef,
		PreferredLanguages: []string{"en"},
	}, secretStore)

	// Local Primary only; no BYO fallback for the demo (fallback nil).
	primary := summarizer.Endpoint{
		Client:   llm.New(cfg.GatewayURL, cfg.GatewayKey, cfg.SummarizerModel, cfg.SummarizerTimeout),
		Provider: "local",
		Model:    cfg.SummarizerModel,
	}
	sum := summarizer.New(primary, nil)

	return usecase.NewEngine(src, sum, st), nil
}

// engineProcessor adapts the engine (which works in terms of a domain.Video) to
// the web.Processor port (which works in terms of a stored video id): it loads the
// video row, runs the engine, and — on a produced summary — clears the manual
// queue flag, mirroring the runner so the video is not re-summarized on the next
// `tapir run` and the UI drops the "Queued" chip. A skip (no transcript) leaves
// the flag set so a later run can retry.
type engineProcessor struct {
	engine *usecase.Engine
	store  *store.Store
}

func (p *engineProcessor) ProcessVideo(ctx context.Context, userID, videoID string) error {
	row, err := p.store.GetVideoRow(ctx, userID, videoID)
	if err != nil {
		return fmt.Errorf("load video %q: %w", videoID, err)
	}

	v := domain.Video{
		ID:              row.VideoID,
		UserID:          userID,
		Provider:        domain.Provider(row.Channel),
		ProviderVideoID: row.ProviderVideoID,
		Title:           row.Title,
		URL:             row.URL,
		PublishedAt:     row.PublishedAt,
	}

	res, err := p.engine.ProcessNewVideo(ctx, v)
	if err != nil {
		return fmt.Errorf("process video %q: %w", videoID, err)
	}
	if res.Summary != nil {
		if err := p.store.ClearSummarizeRequested(ctx, userID, videoID); err != nil {
			return fmt.Errorf("clear summarize flag %q: %w", videoID, err)
		}
	}
	return nil
}
