package postgres

import (
	"context"
	"database/sql"
	"time"

	"switchboard-core/models"
)

type ExtensionPermissionStore struct {
	db *sql.DB
}

func NewExtensionPermissionStore(db *sql.DB) *ExtensionPermissionStore {
	return &ExtensionPermissionStore{db: db}
}

func (s *ExtensionPermissionStore) DeclareForPackage(ctx context.Context, packageID string, permissions []string) error {
	tx, err := s.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// Remove permissions no longer in manifest
	if len(permissions) == 0 {
		_, err = tx.ExecContext(ctx, `DELETE FROM extension_permissions WHERE package_id = $1`, packageID)
		if err != nil {
			return err
		}
		return tx.Commit()
	}

	// Build set of current declared
	declared := make(map[string]bool, len(permissions))
	for _, p := range permissions {
		declared[p] = true
	}

	// Get existing
	rows, err := tx.QueryContext(ctx,
		`SELECT permission FROM extension_permissions WHERE package_id = $1`, packageID)
	if err != nil {
		return err
	}
	existing := make(map[string]bool)
	for rows.Next() {
		var perm string
		if err := rows.Scan(&perm); err != nil {
			rows.Close()
			return err
		}
		existing[perm] = true
	}
	rows.Close()

	// Delete removed
	for perm := range existing {
		if !declared[perm] {
			_, err = tx.ExecContext(ctx,
				`DELETE FROM extension_permissions WHERE package_id = $1 AND permission = $2`,
				packageID, perm)
			if err != nil {
				return err
			}
		}
	}

	// Upsert new (preserving existing grants)
	for _, perm := range permissions {
		if !existing[perm] {
			_, err = tx.ExecContext(ctx,
				`INSERT INTO extension_permissions (id, package_id, permission)
				 VALUES (gen_random_uuid(), $1, $2)
				 ON CONFLICT (package_id, permission) DO NOTHING`,
				packageID, perm)
			if err != nil {
				return err
			}
		}
	}

	return tx.Commit()
}

func (s *ExtensionPermissionStore) ListForPackage(ctx context.Context, packageID string) ([]models.ExtensionPermission, error) {
	rows, err := s.db.QueryContext(ctx,
		`SELECT id, package_id, permission, granted, granted_by, granted_at, created_at
		 FROM extension_permissions
		 WHERE package_id = $1
		 ORDER BY permission`, packageID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var perms []models.ExtensionPermission
	for rows.Next() {
		var p models.ExtensionPermission
		if err := rows.Scan(&p.ID, &p.PackageID, &p.Permission, &p.Granted, &p.GrantedBy, &p.GrantedAt, &p.CreatedAt); err != nil {
			return nil, err
		}
		perms = append(perms, p)
	}
	if perms == nil {
		perms = []models.ExtensionPermission{}
	}
	return perms, nil
}

func (s *ExtensionPermissionStore) GrantedForPackage(ctx context.Context, packageID string) ([]string, error) {
	rows, err := s.db.QueryContext(ctx,
		`SELECT permission FROM extension_permissions
		 WHERE package_id = $1 AND granted = true
		 ORDER BY permission`, packageID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var perms []string
	for rows.Next() {
		var p string
		if err := rows.Scan(&p); err != nil {
			return nil, err
		}
		perms = append(perms, p)
	}
	if perms == nil {
		perms = []string{}
	}
	return perms, nil
}

func (s *ExtensionPermissionStore) Grant(ctx context.Context, packageID, permission, grantedBy string) error {
	now := time.Now()
	_, err := s.db.ExecContext(ctx,
		`UPDATE extension_permissions
		 SET granted = true, granted_by = $1, granted_at = $2
		 WHERE package_id = $3 AND permission = $4`,
		grantedBy, now, packageID, permission)
	return err
}

func (s *ExtensionPermissionStore) Revoke(ctx context.Context, packageID, permission string) error {
	_, err := s.db.ExecContext(ctx,
		`UPDATE extension_permissions
		 SET granted = false, granted_by = NULL, granted_at = NULL
		 WHERE package_id = $1 AND permission = $2`,
		packageID, permission)
	return err
}

func (s *ExtensionPermissionStore) GrantAll(ctx context.Context, packageID, grantedBy string) error {
	now := time.Now()
	_, err := s.db.ExecContext(ctx,
		`UPDATE extension_permissions
		 SET granted = true, granted_by = $1, granted_at = $2
		 WHERE package_id = $3 AND granted = false`,
		grantedBy, now, packageID)
	return err
}

func (s *ExtensionPermissionStore) DeleteForPackage(ctx context.Context, packageID string) error {
	_, err := s.db.ExecContext(ctx,
		`DELETE FROM extension_permissions WHERE package_id = $1`, packageID)
	return err
}
