package client

import (
	"bytes"
	"context"
	"fmt"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

type FileConfig interface {
	GetAccessKeyID() string
	GetAccessKeySecret() string
	GetEndpoint() string
	GetBucketName() string
	GetHostURL() string
}

const _awsRegion = "us-east-1"
const _s3ACL = "public-read"

type S3FileClientImpl struct {
	s3  *s3.S3
	cfg FileConfig
}

func NewFileClient(fileCfg FileConfig) *S3FileClientImpl {
	sess, err := session.NewSession(&aws.Config{
		S3ForcePathStyle: aws.Bool(true),
		Endpoint:         aws.String(fileCfg.GetEndpoint()),
		Region:           aws.String(_awsRegion),
		Credentials:      credentials.NewStaticCredentials(fileCfg.GetAccessKeyID(), fileCfg.GetAccessKeySecret(), ""),
	})

	if err != nil {
		fmt.Println("Failed to create AWS session:", err)
		return nil
	}

	return &S3FileClientImpl{
		s3:  s3.New(sess),
		cfg: fileCfg,
	}
}

func (r *S3FileClientImpl) UploadFile(ctx context.Context, fileName string, fileContent []byte) (fileUrl string, err error) {
	return r.Upload(ctx, r.cfg.GetBucketName(), fileName, fileContent, "application/octet-stream")
}

func (r *S3FileClientImpl) Upload(ctx context.Context, bucket, key string, content []byte, contentType string) (string, error) {
	reader := bytes.NewReader(content)
	_, err := r.s3.PutObjectWithContext(ctx, &s3.PutObjectInput{
		Bucket:      aws.String(bucket),
		Key:         aws.String(key),
		Body:        reader,
		ACL:         aws.String(_s3ACL),
		ContentType: aws.String(contentType),
	})
	if err != nil {
		return "", err
	}
	return r.GetPublicURL(bucket, key), nil
}

// EnsureBucket ensures a bucket exists (idempotent)
func (r *S3FileClientImpl) EnsureBucket(ctx context.Context, bucket string) error {
	_, err := r.s3.HeadBucketWithContext(ctx, &s3.HeadBucketInput{Bucket: aws.String(bucket)})
	if err == nil {
		return nil
	}
	_, err = r.s3.CreateBucketWithContext(ctx, &s3.CreateBucketInput{Bucket: aws.String(bucket)})
	return err
}

func (r *S3FileClientImpl) GetPublicURL(bucket, key string) string {
	if key == "" {
		return ""
	}
	// HostURL expected to include scheme and optional host/path prefix; ensure single slash join
	return fmt.Sprintf("%s%s/%s", r.cfg.GetHostURL(), bucket, key)
}
