package app

import (
	"context"
	"encoding/json"
	"log"
	"strings"
	"time"

	"sub2api-cn-relay-manager/internal/store/sqlite"
	"sub2api-cn-relay-manager/internal/worker"
)

const batchImportBackgroundPollInterval = time.Second

func runBatchImportBackgroundScheduler(ctx context.Context, sqliteDSN string) {
	worker.NewRunner(
		[]worker.Job{batchImportResumeJob{sqliteDSN: sqliteDSN}},
		batchImportBackgroundPollInterval,
		log.Printf,
	).Start(ctx)
}

type batchImportResumeJob struct {
	sqliteDSN string
}

func (j batchImportResumeJob) Name() string {
	return "batch import runtime scheduler"
}

func (j batchImportResumeJob) Run(ctx context.Context) error {
	return resumePendingBatchImportRuns(ctx, j.sqliteDSN)
}

func resumePendingBatchImportRuns(ctx context.Context, sqliteDSN string) error {
	store, err := sqlite.Open(ctx, sqliteDSN)
	if err != nil {
		return err
	}
	defer store.Close()

	runs, err := store.ImportRuns().List(ctx, 1000)
	if err != nil {
		return err
	}
	for _, run := range runs {
		if strings.TrimSpace(run.State) != "running" {
			continue
		}
		runner, err := newBatchImportRuntimeRunnerFromStoredRun(ctx, store, run)
		if err != nil {
			return err
		}
		if err := runner.driveRun(ctx, run.RunID, 0); err != nil {
			return err
		}
	}
	return nil
}

func newBatchImportRuntimeRunnerFromStoredRun(ctx context.Context, store *sqlite.DB, run sqlite.ImportRun) (batchImportRuntimeRunner, error) {
	hostRow, client, err := resolveManagedHost(ctx, store, run.HostID, "", CreateHostAuth{})
	if err != nil {
		return batchImportRuntimeRunner{}, err
	}
	return batchImportRuntimeRunner{
		store:      store,
		hostRow:    hostRow,
		hostClient: client,
		request: CreateBatchImportRunRequest{
			HostID:            run.HostID,
			Mode:              run.Mode,
			AccessMode:        run.AccessMode,
			SubscriptionUsers: parseJSONStringList(run.SubscriptionUsersJSON),
			SubscriptionDays:  run.SubscriptionDays,
			ProbeAPIKey:       run.ProbeAPIKey,
		},
	}, nil
}

func parseJSONStringList(raw string) []string {
	values := []string{}
	if err := json.Unmarshal([]byte(strings.TrimSpace(raw)), &values); err != nil {
		return []string{}
	}
	return values
}
