package db

import (
	"database/sql"
	"errors"
	"fmt"
)

// DeleteManifest deletes the manifest with the given digest from a repository.
// ON DELETE CASCADE handles manifest_blobs and tags rows.
func (d *DB) DeleteManifest(repoID int64, digest string) error {
	result, err := d.Exec(
		`DELETE FROM manifests WHERE repository_id = ? AND digest = ?`,
		repoID, digest,
	)
	if err != nil {
		return fmt.Errorf("db: delete manifest: %w", err)
	}
	n, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("db: delete manifest rows affected: %w", err)
	}
	if n == 0 {
		return ErrManifestNotFound
	}
	return nil
}

// DeleteBlobFromRepo removes the manifest_blobs associations for a blob
// in the given repository. It does NOT delete the blob row or file — that
// is GC's job, since other repositories may reference the same blob.
// Returns ErrBlobNotFound if the blob is not referenced in this repo.
func (d *DB) DeleteBlobFromRepo(repoID int64, digest string) error {
	// First check that the blob exists and is in this repo.
	var blobID int64
	err := d.QueryRow(`SELECT id FROM blobs WHERE digest = ?`, digest).Scan(&blobID)
	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return ErrBlobNotFound
		}
		return fmt.Errorf("db: find blob: %w", err)
	}

	result, err := d.Exec(
		`DELETE FROM manifest_blobs
		 WHERE blob_id = ? AND manifest_id IN (
		     SELECT id FROM manifests WHERE repository_id = ?
		 )`,
		blobID, repoID,
	)
	if err != nil {
		return fmt.Errorf("db: delete blob from repo: %w", err)
	}
	n, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("db: delete blob from repo rows affected: %w", err)
	}
	if n == 0 {
		return ErrBlobNotFound
	}
	return nil
}
