package postgres

import (
	"context"

	"github.com/jackc/pgx/v5"
)

type ManagedAssetRecord struct {
	ID              string
	PublicID        string
	AssetType       string
	AssetCode       string
	Version         string
	Title           *string
	SourceMode      string
	StorageProvider string
	ObjectKey       *string
	PublicURL       string
	FileName        *string
	ContentType     *string
	FileSizeBytes   *int64
	ChecksumSHA256  *string
	Status          string
	MetadataJSONB   map[string]any
}

type CreateManagedAssetParams struct {
	PublicID        string
	AssetType       string
	AssetCode       string
	Version         string
	Title           *string
	SourceMode      string
	StorageProvider string
	ObjectKey       *string
	PublicURL       string
	FileName        *string
	ContentType     *string
	FileSizeBytes   *int64
	ChecksumSHA256  *string
	Status          string
	MetadataJSONB   map[string]any
}

func (s *Store) CreateManagedAsset(ctx context.Context, tx pgx.Tx, params CreateManagedAssetParams) (*ManagedAssetRecord, error) {
	row := tx.QueryRow(ctx, `
		INSERT INTO managed_assets (
			asset_public_id, asset_type, asset_code, version, title, source_mode, storage_provider,
			object_key, public_url, file_name, content_type, file_size_bytes, checksum_sha256, status, metadata_jsonb
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7,
			$8, $9, $10, $11, $12, $13, $14, COALESCE($15, '{}'::jsonb)
		)
		RETURNING id, asset_public_id, asset_type, asset_code, version, title, source_mode, storage_provider,
			object_key, public_url, file_name, content_type, file_size_bytes, checksum_sha256, status, metadata_jsonb
	`,
		params.PublicID, params.AssetType, params.AssetCode, params.Version, params.Title, params.SourceMode, params.StorageProvider,
		params.ObjectKey, params.PublicURL, params.FileName, params.ContentType, params.FileSizeBytes, params.ChecksumSHA256, params.Status, params.MetadataJSONB,
	)
	return scanManagedAsset(row)
}

func (s *Store) ListManagedAssets(ctx context.Context, limit int) ([]ManagedAssetRecord, error) {
	if limit <= 0 {
		limit = 20
	}
	rows, err := s.pool.Query(ctx, `
		SELECT id, asset_public_id, asset_type, asset_code, version, title, source_mode, storage_provider,
			object_key, public_url, file_name, content_type, file_size_bytes, checksum_sha256, status, metadata_jsonb
		FROM managed_assets
		ORDER BY created_at DESC
		LIMIT $1
	`, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var items []ManagedAssetRecord
	for rows.Next() {
		record, err := scanManagedAsset(rows)
		if err != nil {
			return nil, err
		}
		items = append(items, *record)
	}
	return items, rows.Err()
}

func (s *Store) GetManagedAssetByPublicID(ctx context.Context, publicID string) (*ManagedAssetRecord, error) {
	row := s.pool.QueryRow(ctx, `
		SELECT id, asset_public_id, asset_type, asset_code, version, title, source_mode, storage_provider,
			object_key, public_url, file_name, content_type, file_size_bytes, checksum_sha256, status, metadata_jsonb
		FROM managed_assets
		WHERE asset_public_id = $1
	`, publicID)
	return scanManagedAsset(row)
}

type managedAssetScanner interface {
	Scan(dest ...any) error
}

func scanManagedAsset(scanner managedAssetScanner) (*ManagedAssetRecord, error) {
	var record ManagedAssetRecord
	err := scanner.Scan(
		&record.ID,
		&record.PublicID,
		&record.AssetType,
		&record.AssetCode,
		&record.Version,
		&record.Title,
		&record.SourceMode,
		&record.StorageProvider,
		&record.ObjectKey,
		&record.PublicURL,
		&record.FileName,
		&record.ContentType,
		&record.FileSizeBytes,
		&record.ChecksumSHA256,
		&record.Status,
		&record.MetadataJSONB,
	)
	if err != nil {
		if err == pgx.ErrNoRows {
			return nil, nil
		}
		return nil, err
	}
	if record.MetadataJSONB == nil {
		record.MetadataJSONB = map[string]any{}
	}
	return &record, nil
}
