package dbstore

import (
	"context"
	"fmt"

	"git.linuxforward.com/byop/byop-engine/models"
	"gorm.io/gorm"
)

// CreateBuildJob creates a new build job using GORM
func (s *SQLiteStore) CreateBuildJob(ctx context.Context, job *models.BuildJob) error {
	result := s.db.WithContext(ctx).Create(job)
	if result.Error != nil {
		return fmt.Errorf("failed to create build job: %w", result.Error)
	}
	return nil
}

// GetBuildJobByID retrieves a build job by ID using GORM
func (s *SQLiteStore) GetBuildJobByID(ctx context.Context, id uint) (*models.BuildJob, error) {
	var job models.BuildJob
	result := s.db.WithContext(ctx).First(&job, id)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			return nil, models.NewErrNotFound(fmt.Sprintf("build job with ID %d not found", id), result.Error)
		}
		return nil, fmt.Errorf("failed to get build job by ID: %w", result.Error)
	}
	return &job, nil
}

// UpdateBuildJob updates an existing build job using GORM
func (s *SQLiteStore) UpdateBuildJob(ctx context.Context, job *models.BuildJob) error {
	result := s.db.WithContext(ctx).Save(job)
	if result.Error != nil {
		return fmt.Errorf("failed to update build job: %w", result.Error)
	}
	if result.RowsAffected == 0 {
		return models.NewErrNotFound(fmt.Sprintf("build job with ID %d not found for update", job.ID), nil)
	}
	return nil
}

// UpdateBuildJobStatus updates the status and error message of a build job using GORM
func (s *SQLiteStore) UpdateBuildJobStatus(ctx context.Context, id uint, status models.BuildStatus, errorMessage string) error {
	result := s.db.WithContext(ctx).Model(&models.BuildJob{}).Where("id = ?", id).Updates(map[string]interface{}{
		"status":        status,
		"error_message": errorMessage,
	})
	if result.Error != nil {
		return fmt.Errorf("failed to update build job status: %w", result.Error)
	}
	if result.RowsAffected == 0 {
		return models.NewErrNotFound(fmt.Sprintf("build job with ID %d not found for status update", id), nil)
	}
	return nil
}

// AppendBuildJobLog appends a log message to a build job using GORM
func (s *SQLiteStore) AppendBuildJobLog(ctx context.Context, id uint, logMessage string) error {
	// Get current logs first
	var job models.BuildJob
	result := s.db.WithContext(ctx).Select("logs").First(&job, id)
	if result.Error != nil {
		if result.Error == gorm.ErrRecordNotFound {
			return models.NewErrNotFound(fmt.Sprintf("build job with ID %d not found", id), result.Error)
		}
		return fmt.Errorf("failed to get build job for log append: %w", result.Error)
	}

	// Append new log message
	newLogs := job.Logs + logMessage + "\n"
	result = s.db.WithContext(ctx).Model(&models.BuildJob{}).Where("id = ?", id).Update("logs", newLogs)
	if result.Error != nil {
		return fmt.Errorf("failed to append build job log: %w", result.Error)
	}
	return nil
}

// GetQueuedBuildJobs retrieves queued build jobs using GORM
func (s *SQLiteStore) GetQueuedBuildJobs(ctx context.Context, limit int) ([]*models.BuildJob, error) {
	var jobs []*models.BuildJob
	result := s.db.WithContext(ctx).Where("status = ?", models.BuildStatusPending).Limit(limit).Find(&jobs)
	if result.Error != nil {
		return nil, fmt.Errorf("failed to get queued build jobs: %w", result.Error)
	}
	return jobs, nil
}

// GetBuildJobsByAppID retrieves build jobs for a specific app using GORM (with pagination)
func (s *SQLiteStore) GetBuildJobsByAppID(ctx context.Context, appID uint, page, pageSize int) ([]*models.BuildJob, int64, error) {
	var jobs []*models.BuildJob
	var total int64

	// Count total records
	s.db.WithContext(ctx).Model(&models.BuildJob{}).Where("component_id IN (SELECT id FROM components WHERE user_id = (SELECT user_id FROM apps WHERE id = ?))", appID).Count(&total)

	// Get paginated results
	offset := (page - 1) * pageSize
	result := s.db.WithContext(ctx).Where("component_id IN (SELECT id FROM components WHERE user_id = (SELECT user_id FROM apps WHERE id = ?))", appID).
		Offset(offset).Limit(pageSize).Find(&jobs)

	if result.Error != nil {
		return nil, 0, fmt.Errorf("failed to get build jobs by app ID: %w", result.Error)
	}
	return jobs, total, nil
}
