package storage

import (
	"context"
	"fmt"
	"log"
	"photum-backend/internal/config"
	"time"

	"github.com/aws/aws-sdk-go-v2/aws"
	awsConfig "github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/credentials"
	"github.com/aws/aws-sdk-go-v2/service/s3"
)

type S3Service struct {
	Client        *s3.Client
	PresignClient *s3.PresignClient
	Bucket        string
	Region        string
}

func NewS3Service(cfg *config.Config) *S3Service {
	// Custom Resolver for Civo Object Store
	customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
		return aws.Endpoint{
			URL:           cfg.S3Endpoint,
			SigningRegion: region,
		}, nil
	})

	awsCfg, err := awsConfig.LoadDefaultConfig(context.TODO(),
		awsConfig.WithRegion(cfg.S3Region),
		awsConfig.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(cfg.S3AccessKey, cfg.S3SecretKey, "")),
		awsConfig.WithEndpointResolverWithOptions(customResolver),
	)
	if err != nil {
		log.Fatalf("unable to load SDK config, %v", err)
	}

	client := s3.NewFromConfig(awsCfg, func(o *s3.Options) {
		o.UsePathStyle = true
	})
	presignClient := s3.NewPresignClient(client)

	return &S3Service{
		Client:        client,
		PresignClient: presignClient,
		Bucket:        cfg.S3Bucket,
		Region:        cfg.S3Region,
	}
}

// GeneratePresignedURL generates a PUT presigned URL for uploading a file
// returns (uploadUrl, publicUrl, error)
func (s *S3Service) GeneratePresignedURL(filename string, contentType string) (string, string, error) {
	key := fmt.Sprintf("photum-dev/%d_%s", time.Now().Unix(), filename)

	req, err := s.PresignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{
		Bucket:      aws.String(s.Bucket),
		Key:         aws.String(key),
		ContentType: aws.String(contentType),
	}, s3.WithPresignExpires(15*time.Minute))

	if err != nil {
		return "", "", fmt.Errorf("failed to sign request: %v", err)
	}

	// Construct public URL - Path Style
	// URL: https://objectstore.nyc1.civo.com/rede5/uploads/...
	// We need to clean the endpoint string if it has https:// prefix for Sprintf if we construct manually,
	// or just reuse the known endpoint structure.
	// cfg.S3Endpoint is "https://objectstore.nyc1.civo.com"

	// Assuming s.Client.Options().BaseEndpoint is not easily accessible here without plumbing,
	// we will construct it based on the hardcoded knowledge of Civo or pass endpoint to struct.
	// But simply: S3Endpoint + "/" + Bucket + "/" + key is the standard path style.

	// Note: config.S3Endpoint includes "https://" based on .env
	// We entered: S3_ENDPOINT=https://objectstore.nyc1.civo.com

	// So: https://objectstore.nyc1.civo.com/rede5/key

	// However, we don't have access to cfg here directly, but we rely on hardcoding for Civo in previous step or we should store Endpoint in struct.
	// Better to store Endpoint in struct to be clean.
	// For now, I'll use the domain directly as I did before, but path style.

	publicURL := fmt.Sprintf("https://%s/%s/%s", "objectstore.nyc1.civo.com", s.Bucket, key)

	return req.URL, publicURL, nil
}
