package data

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"git.vdhsn.com/barretthousen/barretthousen/src/runner/internal/data/postgres"
	"git.vdhsn.com/barretthousen/barretthousen/src/runner/internal/domain"
)

type PGRunnerStorage struct {
	*postgres.Queries
}

func (db *PGRunnerStorage) CreateScrapeJob(ctx context.Context, target string) (sj domain.ScrapeJob, err error) {
	if target == "" {
		target = "ALL"
	}

	rsj, err := db.Queries.CreateScrapeJob(ctx, target)
	if err != nil {
		return domain.ScrapeJob{}, err
	}

	return domain.ScrapeJob{
		ID:         int(rsj.ID),
		Started:    rsj.Startedts,
		TargetSite: rsj.Targetsitename,
	}, nil
}

func (db *PGRunnerStorage) CompleteScrapeJob(ctx context.Context, ID int, status domain.CompleteScrapeJobStatus) (sj domain.ScrapeJob, err error) {
	completedTime := time.Now().UTC()
	if err = db.Queries.CompleteScrapeJob(ctx, postgres.CompleteScrapeJobParams{
		ID: int32(ID),
		Completedts: sql.NullTime{
			Time:  completedTime,
			Valid: true,
		},
		Auctionsfound: int32(status.AuctionCount),
		Errors:        status.Errors,
	}); err != nil {
		err = fmt.Errorf("could update scrape job in DB: %w", err)
		return
	}

	var rsj postgres.RunnerScrapejob
	if rsj, err = db.Queries.GetJobByID(ctx, int32(ID)); err != nil {
		err = fmt.Errorf("could not get job by ID: %w", err)
		return
	}

	sj = domain.ScrapeJob{
		ID:            ID,
		Started:       rsj.Startedts,
		Completed:     completedTime,
		TargetSite:    rsj.Targetsitename,
		AuctionsFound: status.AuctionCount,
		Errors:        status.Errors,
	}

	return
}

func (db *PGRunnerStorage) GetJobs(ctx context.Context, page int32, limit int32) (out domain.GetJobsResult, err error) {
	var completeJobs []postgres.RunnerScrapejob
	if completeJobs, err = db.Queries.GetCompletedJobs(ctx, postgres.GetCompletedJobsParams{
		Page:     page,
		Pagesize: limit,
	}); err != nil {
		err = fmt.Errorf("Couldn't get jobs from DB: %w", err)
		return
	}

	var activeJobs []postgres.RunnerScrapejob
	if activeJobs, err = db.Queries.GetActiveJobs(ctx, postgres.GetActiveJobsParams{
		Page:     0,
		Pagesize: 64,
	}); err != nil {
		err = fmt.Errorf("Couldn't get jobs from DB: %w", err)
		return
	}

	var jobCounts postgres.GetJobCountsRow
	if jobCounts, err = db.Queries.GetJobCounts(ctx); err != nil {
		err = fmt.Errorf("couldn't get total job count: %w", err)
		return
	}

	out.Total = int(jobCounts.Total)
	out.ActiveTotal = int(jobCounts.Active)
	out.CompletedTotal = int(jobCounts.Completed)
	out.Active = mapScrapeJob(activeJobs)
	out.Complete = mapScrapeJob(completeJobs)

	return
}

func mapScrapeJob(jobs []postgres.RunnerScrapejob) (result []domain.ScrapeJob) {
	result = make([]domain.ScrapeJob, len(jobs))
	for i, j := range jobs {
		result[i] = domain.ScrapeJob{
			ID:            int(j.ID),
			Started:       j.Startedts,
			TargetSite:    j.Targetsitename,
			AuctionsFound: int(j.Auctionsfound),
			Errors:        j.Errors,
		}

		if j.Completedts.Valid {
			result[i].Completed = j.Completedts.Time
		}
	}

	return
}
