package store

import (
	"context"
	"encoding/json"
)

// PackageStore manages the unified package registry (surfaces + extensions).
// Replaces SurfaceRegistryStore and ExtensionStore (v0.28.7).
type PackageStore interface {
	// ── Lifecycle (from SurfaceRegistryStore) ────────────

	// Seed upserts a package at startup. Does NOT overwrite the enabled
	// flag if the row already exists (admin toggle survives restarts).
	// Called by the page engine for core surfaces.
	Seed(ctx context.Context, id, title, source string, manifest map[string]any) error

	// List returns all registered packages, ordered by source then title.
	List(ctx context.Context) ([]PackageRegistration, error)

	// Get returns a single package by ID (slug).
	Get(ctx context.Context, id string) (*PackageRegistration, error)

	// SetEnabled toggles a package's enabled state.
	SetEnabled(ctx context.Context, id string, enabled bool) error

	// SetStatus transitions a package's lifecycle status.
	// Valid statuses: active, pending_review, suspended, dormant.
	SetStatus(ctx context.Context, id string, status string) error

	// Delete removes a non-core package. Core packages cannot be deleted.
	Delete(ctx context.Context, id string) error

	// ListEnabled returns IDs of all enabled packages.
	// Used by the page engine for nav rendering, not exposed via HTTP.
	ListEnabled(ctx context.Context) ([]string, error)

	// ── Extended lifecycle ───────────────────────────────

	// Create inserts a new package with all fields. Used by the install
	// handler for .pkg uploads.
	Create(ctx context.Context, pkg *PackageRegistration) error

	// Update modifies mutable fields on an existing package.
	Update(ctx context.Context, id string, pkg *PackageRegistration) error

	// ListByType returns packages filtered by type (surface, extension, full).
	ListByType(ctx context.Context, pkgType string) ([]PackageRegistration, error)

	// ListEnabledByType returns enabled packages of a given type.
	ListEnabledByType(ctx context.Context, pkgType string) ([]PackageRegistration, error)

	// ── Extension runtime (from ExtensionStore) ─────────

	// ListForUser returns enabled extension/full packages with per-user
	// settings overlay from package_user_settings. System packages are
	// always included (users can't disable them).
	ListForUser(ctx context.Context, userID string) ([]UserPackage, error)

	// GetUserSettings returns per-user settings for a specific package.
	GetUserSettings(ctx context.Context, pkgID, userID string) (*PackageUserSettings, error)

	// SetUserSettings upserts per-user settings for a package.
	SetUserSettings(ctx context.Context, s *PackageUserSettings) error

	// DeleteUserSettings removes per-user settings, reverting to defaults.
	DeleteUserSettings(ctx context.Context, pkgID, userID string) error

	// ── Scoped visibility (v0.30.0) ────────────────

	// ListVisiblePackages returns packages visible to the given user:
	// global packages + team packages for user's teams + personal packages.
	ListVisiblePackages(ctx context.Context, userID string) ([]PackageRegistration, error)

	// ── Package lifecycle (v0.30.0) ─────────────────

	// SetSchemaVersion updates the current schema version for a package.
	SetSchemaVersion(ctx context.Context, id string, version int) error

	// GetPackageSettings returns the admin-configured package-level settings.
	GetPackageSettings(ctx context.Context, id string) (json.RawMessage, error)

	// SetPackageSettings stores admin-configured package-level settings.
	SetPackageSettings(ctx context.Context, id string, settings json.RawMessage) error

	// ── Team-level settings (v0.2.0) ─────────────────

	// GetTeamSettings returns team-scoped overrides for a package.
	GetTeamSettings(ctx context.Context, pkgID, teamID string) (json.RawMessage, error)

	// SetTeamSettings upserts team-scoped overrides for a package.
	SetTeamSettings(ctx context.Context, pkgID, teamID string, settings json.RawMessage) error

	// DeleteTeamSettings removes team-scoped overrides, reverting to global defaults.
	DeleteTeamSettings(ctx context.Context, pkgID, teamID string) error
}

// PackageRegistration is a row from the packages table.
type PackageRegistration struct {
	ID          string         `json:"id" db:"id"`
	Title       string         `json:"title" db:"title"`
	Type        string         `json:"type" db:"type"`
	Version     string         `json:"version" db:"version"`
	Description string         `json:"description" db:"description"`
	Author      string         `json:"author" db:"author"`
	Tier        string         `json:"tier" db:"tier"`
	IsSystem    bool           `json:"is_system" db:"is_system"`
	Scope       string         `json:"scope" db:"scope"`
	TeamID      *string        `json:"team_id,omitempty" db:"team_id"`
	InstalledBy *string        `json:"installed_by,omitempty" db:"installed_by"`
	Manifest    map[string]any `json:"manifest" db:"manifest"`
	Enabled     bool           `json:"enabled" db:"enabled"`
	Status      string         `json:"status" db:"status"`
	SchemaVersion   int             `json:"schema_version" db:"schema_version"`
	PackageSettings json.RawMessage `json:"package_settings" db:"package_settings"`
	Source          string          `json:"source" db:"source"`
	InstalledAt     string          `json:"installed_at" db:"installed_at"`
	UpdatedAt       string          `json:"updated_at" db:"updated_at"`
}

// UserPackage combines package info with per-user settings for API responses.
// Returned by ListForUser for the /extensions endpoint.
type UserPackage struct {
	PackageRegistration
	UserEnabled  *bool            `json:"user_enabled,omitempty"`
	UserSettings *json.RawMessage `json:"user_settings,omitempty"`
}

// PackageUserSettings stores per-user overrides for a package.
type PackageUserSettings struct {
	PackageID string          `json:"package_id" db:"package_id"`
	UserID    string          `json:"user_id" db:"user_id"`
	Settings  json.RawMessage `json:"settings" db:"settings"`
	IsEnabled bool            `json:"is_enabled" db:"is_enabled"`
}

// PackageTeamSettings stores team-scoped overrides for a package (v0.2.0).
type PackageTeamSettings struct {
	PackageID string          `json:"package_id" db:"package_id"`
	TeamID    string          `json:"team_id" db:"team_id"`
	Settings  json.RawMessage `json:"settings" db:"settings"`
	UpdatedAt string          `json:"updated_at" db:"updated_at"`
}
