package policy

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgxpool"
)

// Store provides database operations for the policy system.
type Store struct {
	pool *pgxpool.Pool
}

// NewStore creates a new Store instance.
func NewStore(pool *pgxpool.Pool) *Store {
	return &Store{pool: pool}
}

// =============================================================================
// SOURCE POLICIES
// =============================================================================

// CreatePolicy creates a new source policy.
func (s *Store) CreatePolicy(ctx context.Context, req *CreateSourcePolicyRequest) (*SourcePolicy, error) {
	policy := &SourcePolicy{
		ID:         uuid.New(),
		Version:    1,
		Name:       req.Name,
		Description: req.Description,
		Bundesland: req.Bundesland,
		IsActive:   true,
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
	}

	query := `
		INSERT INTO source_policies (id, version, name, description, bundesland, is_active, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
		RETURNING id, version, name, description, bundesland, is_active, created_at, updated_at`

	err := s.pool.QueryRow(ctx, query,
		policy.ID, policy.Version, policy.Name, policy.Description,
		policy.Bundesland, policy.IsActive, policy.CreatedAt, policy.UpdatedAt,
	).Scan(
		&policy.ID, &policy.Version, &policy.Name, &policy.Description,
		&policy.Bundesland, &policy.IsActive, &policy.CreatedAt, &policy.UpdatedAt,
	)

	if err != nil {
		return nil, fmt.Errorf("failed to create policy: %w", err)
	}

	return policy, nil
}

// GetPolicy retrieves a policy by ID.
func (s *Store) GetPolicy(ctx context.Context, id uuid.UUID) (*SourcePolicy, error) {
	query := `
		SELECT id, version, name, description, bundesland, is_active,
		       created_at, updated_at, approved_by, approved_at
		FROM source_policies
		WHERE id = $1`

	policy := &SourcePolicy{}
	err := s.pool.QueryRow(ctx, query, id).Scan(
		&policy.ID, &policy.Version, &policy.Name, &policy.Description,
		&policy.Bundesland, &policy.IsActive, &policy.CreatedAt, &policy.UpdatedAt,
		&policy.ApprovedBy, &policy.ApprovedAt,
	)

	if err == pgx.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get policy: %w", err)
	}

	return policy, nil
}

// ListPolicies retrieves policies with optional filters.
func (s *Store) ListPolicies(ctx context.Context, filter *PolicyListFilter) ([]SourcePolicy, int, error) {
	baseQuery := `FROM source_policies WHERE 1=1`
	args := []interface{}{}
	argCount := 0

	if filter.Bundesland != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND bundesland = $%d", argCount)
		args = append(args, *filter.Bundesland)
	}

	if filter.IsActive != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND is_active = $%d", argCount)
		args = append(args, *filter.IsActive)
	}

	// Count query
	var total int
	countQuery := "SELECT COUNT(*) " + baseQuery
	err := s.pool.QueryRow(ctx, countQuery, args...).Scan(&total)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to count policies: %w", err)
	}

	// Data query with pagination
	dataQuery := `SELECT id, version, name, description, bundesland, is_active,
	              created_at, updated_at, approved_by, approved_at ` + baseQuery +
		` ORDER BY created_at DESC`

	if filter.Limit > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" LIMIT $%d", argCount)
		args = append(args, filter.Limit)
	}
	if filter.Offset > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" OFFSET $%d", argCount)
		args = append(args, filter.Offset)
	}

	rows, err := s.pool.Query(ctx, dataQuery, args...)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list policies: %w", err)
	}
	defer rows.Close()

	policies := []SourcePolicy{}
	for rows.Next() {
		var p SourcePolicy
		err := rows.Scan(
			&p.ID, &p.Version, &p.Name, &p.Description,
			&p.Bundesland, &p.IsActive, &p.CreatedAt, &p.UpdatedAt,
			&p.ApprovedBy, &p.ApprovedAt,
		)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to scan policy: %w", err)
		}
		policies = append(policies, p)
	}

	return policies, total, nil
}

// UpdatePolicy updates an existing policy.
func (s *Store) UpdatePolicy(ctx context.Context, id uuid.UUID, req *UpdateSourcePolicyRequest) (*SourcePolicy, error) {
	policy, err := s.GetPolicy(ctx, id)
	if err != nil {
		return nil, err
	}
	if policy == nil {
		return nil, fmt.Errorf("policy not found")
	}

	if req.Name != nil {
		policy.Name = *req.Name
	}
	if req.Description != nil {
		policy.Description = req.Description
	}
	if req.Bundesland != nil {
		policy.Bundesland = req.Bundesland
	}
	if req.IsActive != nil {
		policy.IsActive = *req.IsActive
	}
	policy.Version++
	policy.UpdatedAt = time.Now()

	query := `
		UPDATE source_policies
		SET version = $2, name = $3, description = $4, bundesland = $5,
		    is_active = $6, updated_at = $7
		WHERE id = $1
		RETURNING id, version, name, description, bundesland, is_active, created_at, updated_at`

	err = s.pool.QueryRow(ctx, query,
		id, policy.Version, policy.Name, policy.Description,
		policy.Bundesland, policy.IsActive, policy.UpdatedAt,
	).Scan(
		&policy.ID, &policy.Version, &policy.Name, &policy.Description,
		&policy.Bundesland, &policy.IsActive, &policy.CreatedAt, &policy.UpdatedAt,
	)

	if err != nil {
		return nil, fmt.Errorf("failed to update policy: %w", err)
	}

	return policy, nil
}

// DeletePolicy deletes a policy by ID (soft delete via is_active = false).
func (s *Store) DeletePolicy(ctx context.Context, id uuid.UUID) error {
	query := `UPDATE source_policies SET is_active = false, updated_at = $2 WHERE id = $1`
	_, err := s.pool.Exec(ctx, query, id, time.Now())
	if err != nil {
		return fmt.Errorf("failed to delete policy: %w", err)
	}
	return nil
}

// =============================================================================
// ALLOWED SOURCES
// =============================================================================

// CreateSource creates a new allowed source.
func (s *Store) CreateSource(ctx context.Context, req *CreateAllowedSourceRequest) (*AllowedSource, error) {
	trustBoost := 0.5
	if req.TrustBoost != nil {
		trustBoost = *req.TrustBoost
	}

	source := &AllowedSource{
		ID:               uuid.New(),
		PolicyID:         req.PolicyID,
		Domain:           req.Domain,
		Name:             req.Name,
		Description:      req.Description,
		License:          req.License,
		LegalBasis:       req.LegalBasis,
		CitationTemplate: req.CitationTemplate,
		TrustBoost:       trustBoost,
		IsActive:         true,
		CreatedAt:        time.Now(),
		UpdatedAt:        time.Now(),
	}

	query := `
		INSERT INTO allowed_sources (id, policy_id, domain, name, description, license,
		                             legal_basis, citation_template, trust_boost, is_active,
		                             created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
		RETURNING id`

	err := s.pool.QueryRow(ctx, query,
		source.ID, source.PolicyID, source.Domain, source.Name, source.Description,
		source.License, source.LegalBasis, source.CitationTemplate, source.TrustBoost,
		source.IsActive, source.CreatedAt, source.UpdatedAt,
	).Scan(&source.ID)

	if err != nil {
		return nil, fmt.Errorf("failed to create source: %w", err)
	}

	// Create default operation permissions
	err = s.createDefaultOperations(ctx, source.ID)
	if err != nil {
		return nil, fmt.Errorf("failed to create default operations: %w", err)
	}

	return source, nil
}

// createDefaultOperations creates default operation permissions for a source.
func (s *Store) createDefaultOperations(ctx context.Context, sourceID uuid.UUID) error {
	defaults := []struct {
		op       Operation
		allowed  bool
		citation bool
	}{
		{OperationLookup, true, true},
		{OperationRAG, true, true},
		{OperationTraining, false, false}, // VERBOTEN by default
		{OperationExport, true, true},
	}

	for _, d := range defaults {
		query := `
			INSERT INTO operation_permissions (id, source_id, operation, is_allowed, requires_citation, created_at, updated_at)
			VALUES ($1, $2, $3, $4, $5, $6, $7)`
		_, err := s.pool.Exec(ctx, query, uuid.New(), sourceID, d.op, d.allowed, d.citation, time.Now(), time.Now())
		if err != nil {
			return err
		}
	}
	return nil
}

// GetSource retrieves a source by ID.
func (s *Store) GetSource(ctx context.Context, id uuid.UUID) (*AllowedSource, error) {
	query := `
		SELECT als.id, als.policy_id, als.domain, als.name, als.description, als.license,
		       als.legal_basis, als.citation_template, als.trust_boost, als.is_active,
		       als.created_at, als.updated_at, sp.name as policy_name
		FROM allowed_sources als
		JOIN source_policies sp ON als.policy_id = sp.id
		WHERE als.id = $1`

	source := &AllowedSource{}
	err := s.pool.QueryRow(ctx, query, id).Scan(
		&source.ID, &source.PolicyID, &source.Domain, &source.Name, &source.Description,
		&source.License, &source.LegalBasis, &source.CitationTemplate, &source.TrustBoost,
		&source.IsActive, &source.CreatedAt, &source.UpdatedAt, &source.PolicyName,
	)

	if err == pgx.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get source: %w", err)
	}

	// Load operations
	ops, err := s.GetOperationsBySourceID(ctx, source.ID)
	if err != nil {
		return nil, err
	}
	source.Operations = ops

	return source, nil
}

// GetSourceByDomain retrieves a source by domain with optional bundesland filter.
func (s *Store) GetSourceByDomain(ctx context.Context, domain string, bundesland *Bundesland) (*AllowedSource, error) {
	query := `
		SELECT als.id, als.policy_id, als.domain, als.name, als.description, als.license,
		       als.legal_basis, als.citation_template, als.trust_boost, als.is_active,
		       als.created_at, als.updated_at
		FROM allowed_sources als
		JOIN source_policies sp ON als.policy_id = sp.id
		WHERE als.is_active = true
		  AND sp.is_active = true
		  AND (als.domain = $1 OR $1 LIKE '%.' || als.domain)
		  AND (sp.bundesland IS NULL OR sp.bundesland = $2)
		LIMIT 1`

	source := &AllowedSource{}
	err := s.pool.QueryRow(ctx, query, domain, bundesland).Scan(
		&source.ID, &source.PolicyID, &source.Domain, &source.Name, &source.Description,
		&source.License, &source.LegalBasis, &source.CitationTemplate, &source.TrustBoost,
		&source.IsActive, &source.CreatedAt, &source.UpdatedAt,
	)

	if err == pgx.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get source by domain: %w", err)
	}

	// Load operations
	ops, err := s.GetOperationsBySourceID(ctx, source.ID)
	if err != nil {
		return nil, err
	}
	source.Operations = ops

	return source, nil
}

// ListSources retrieves sources with optional filters.
func (s *Store) ListSources(ctx context.Context, filter *SourceListFilter) ([]AllowedSource, int, error) {
	baseQuery := `FROM allowed_sources als JOIN source_policies sp ON als.policy_id = sp.id WHERE 1=1`
	args := []interface{}{}
	argCount := 0

	if filter.PolicyID != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND als.policy_id = $%d", argCount)
		args = append(args, *filter.PolicyID)
	}

	if filter.Domain != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND als.domain ILIKE $%d", argCount)
		args = append(args, "%"+*filter.Domain+"%")
	}

	if filter.License != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND als.license = $%d", argCount)
		args = append(args, *filter.License)
	}

	if filter.IsActive != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND als.is_active = $%d", argCount)
		args = append(args, *filter.IsActive)
	}

	// Count query
	var total int
	countQuery := "SELECT COUNT(*) " + baseQuery
	err := s.pool.QueryRow(ctx, countQuery, args...).Scan(&total)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to count sources: %w", err)
	}

	// Data query
	dataQuery := `SELECT als.id, als.policy_id, als.domain, als.name, als.description, als.license,
	              als.legal_basis, als.citation_template, als.trust_boost, als.is_active,
	              als.created_at, als.updated_at, sp.name as policy_name ` + baseQuery +
		` ORDER BY als.created_at DESC`

	if filter.Limit > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" LIMIT $%d", argCount)
		args = append(args, filter.Limit)
	}
	if filter.Offset > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" OFFSET $%d", argCount)
		args = append(args, filter.Offset)
	}

	rows, err := s.pool.Query(ctx, dataQuery, args...)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list sources: %w", err)
	}
	defer rows.Close()

	sources := []AllowedSource{}
	for rows.Next() {
		var src AllowedSource
		err := rows.Scan(
			&src.ID, &src.PolicyID, &src.Domain, &src.Name, &src.Description,
			&src.License, &src.LegalBasis, &src.CitationTemplate, &src.TrustBoost,
			&src.IsActive, &src.CreatedAt, &src.UpdatedAt, &src.PolicyName,
		)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to scan source: %w", err)
		}
		sources = append(sources, src)
	}

	return sources, total, nil
}

// UpdateSource updates an existing source.
func (s *Store) UpdateSource(ctx context.Context, id uuid.UUID, req *UpdateAllowedSourceRequest) (*AllowedSource, error) {
	source, err := s.GetSource(ctx, id)
	if err != nil {
		return nil, err
	}
	if source == nil {
		return nil, fmt.Errorf("source not found")
	}

	if req.Domain != nil {
		source.Domain = *req.Domain
	}
	if req.Name != nil {
		source.Name = *req.Name
	}
	if req.Description != nil {
		source.Description = req.Description
	}
	if req.License != nil {
		source.License = *req.License
	}
	if req.LegalBasis != nil {
		source.LegalBasis = req.LegalBasis
	}
	if req.CitationTemplate != nil {
		source.CitationTemplate = req.CitationTemplate
	}
	if req.TrustBoost != nil {
		source.TrustBoost = *req.TrustBoost
	}
	if req.IsActive != nil {
		source.IsActive = *req.IsActive
	}
	source.UpdatedAt = time.Now()

	query := `
		UPDATE allowed_sources
		SET domain = $2, name = $3, description = $4, license = $5, legal_basis = $6,
		    citation_template = $7, trust_boost = $8, is_active = $9, updated_at = $10
		WHERE id = $1`

	_, err = s.pool.Exec(ctx, query,
		id, source.Domain, source.Name, source.Description, source.License,
		source.LegalBasis, source.CitationTemplate, source.TrustBoost,
		source.IsActive, source.UpdatedAt,
	)

	if err != nil {
		return nil, fmt.Errorf("failed to update source: %w", err)
	}

	return source, nil
}

// DeleteSource deletes a source by ID.
func (s *Store) DeleteSource(ctx context.Context, id uuid.UUID) error {
	query := `DELETE FROM allowed_sources WHERE id = $1`
	_, err := s.pool.Exec(ctx, query, id)
	if err != nil {
		return fmt.Errorf("failed to delete source: %w", err)
	}
	return nil
}

// =============================================================================
// OPERATION PERMISSIONS
// =============================================================================

// GetOperationsBySourceID retrieves all operation permissions for a source.
func (s *Store) GetOperationsBySourceID(ctx context.Context, sourceID uuid.UUID) ([]OperationPermission, error) {
	query := `
		SELECT id, source_id, operation, is_allowed, requires_citation, notes, created_at, updated_at
		FROM operation_permissions
		WHERE source_id = $1
		ORDER BY operation`

	rows, err := s.pool.Query(ctx, query, sourceID)
	if err != nil {
		return nil, fmt.Errorf("failed to get operations: %w", err)
	}
	defer rows.Close()

	ops := []OperationPermission{}
	for rows.Next() {
		var op OperationPermission
		err := rows.Scan(
			&op.ID, &op.SourceID, &op.Operation, &op.IsAllowed,
			&op.RequiresCitation, &op.Notes, &op.CreatedAt, &op.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan operation: %w", err)
		}
		ops = append(ops, op)
	}

	return ops, nil
}

// UpdateOperationPermission updates an operation permission.
func (s *Store) UpdateOperationPermission(ctx context.Context, id uuid.UUID, req *UpdateOperationPermissionRequest) (*OperationPermission, error) {
	query := `SELECT id, source_id, operation, is_allowed, requires_citation, notes, created_at, updated_at
	          FROM operation_permissions WHERE id = $1`

	op := &OperationPermission{}
	err := s.pool.QueryRow(ctx, query, id).Scan(
		&op.ID, &op.SourceID, &op.Operation, &op.IsAllowed,
		&op.RequiresCitation, &op.Notes, &op.CreatedAt, &op.UpdatedAt,
	)
	if err == pgx.ErrNoRows {
		return nil, fmt.Errorf("operation permission not found")
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get operation: %w", err)
	}

	if req.IsAllowed != nil {
		op.IsAllowed = *req.IsAllowed
	}
	if req.RequiresCitation != nil {
		op.RequiresCitation = *req.RequiresCitation
	}
	if req.Notes != nil {
		op.Notes = req.Notes
	}
	op.UpdatedAt = time.Now()

	updateQuery := `
		UPDATE operation_permissions
		SET is_allowed = $2, requires_citation = $3, notes = $4, updated_at = $5
		WHERE id = $1`

	_, err = s.pool.Exec(ctx, updateQuery, id, op.IsAllowed, op.RequiresCitation, op.Notes, op.UpdatedAt)
	if err != nil {
		return nil, fmt.Errorf("failed to update operation: %w", err)
	}

	return op, nil
}

// GetOperationsMatrix retrieves all operation permissions grouped by source.
func (s *Store) GetOperationsMatrix(ctx context.Context) ([]AllowedSource, error) {
	query := `
		SELECT als.id, als.domain, als.name, als.license, als.is_active,
		       sp.name as policy_name, sp.bundesland
		FROM allowed_sources als
		JOIN source_policies sp ON als.policy_id = sp.id
		WHERE als.is_active = true AND sp.is_active = true
		ORDER BY sp.bundesland NULLS FIRST, als.name`

	rows, err := s.pool.Query(ctx, query)
	if err != nil {
		return nil, fmt.Errorf("failed to get operations matrix: %w", err)
	}
	defer rows.Close()

	sources := []AllowedSource{}
	for rows.Next() {
		var src AllowedSource
		var bundesland *Bundesland
		err := rows.Scan(
			&src.ID, &src.Domain, &src.Name, &src.License, &src.IsActive,
			&src.PolicyName, &bundesland,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan source: %w", err)
		}

		// Load operations for each source
		ops, err := s.GetOperationsBySourceID(ctx, src.ID)
		if err != nil {
			return nil, err
		}
		src.Operations = ops
		sources = append(sources, src)
	}

	return sources, nil
}

// =============================================================================
// PII RULES
// =============================================================================

// CreatePIIRule creates a new PII rule.
func (s *Store) CreatePIIRule(ctx context.Context, req *CreatePIIRuleRequest) (*PIIRule, error) {
	severity := PIISeverityBlock
	if req.Severity != "" {
		severity = req.Severity
	}

	rule := &PIIRule{
		ID:          uuid.New(),
		Name:        req.Name,
		Description: req.Description,
		RuleType:    req.RuleType,
		Pattern:     req.Pattern,
		Severity:    severity,
		IsActive:    true,
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}

	query := `
		INSERT INTO pii_rules (id, name, description, rule_type, pattern, severity, is_active, created_at, updated_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
		RETURNING id`

	err := s.pool.QueryRow(ctx, query,
		rule.ID, rule.Name, rule.Description, rule.RuleType, rule.Pattern,
		rule.Severity, rule.IsActive, rule.CreatedAt, rule.UpdatedAt,
	).Scan(&rule.ID)

	if err != nil {
		return nil, fmt.Errorf("failed to create PII rule: %w", err)
	}

	return rule, nil
}

// GetPIIRule retrieves a PII rule by ID.
func (s *Store) GetPIIRule(ctx context.Context, id uuid.UUID) (*PIIRule, error) {
	query := `
		SELECT id, name, description, rule_type, pattern, severity, is_active, created_at, updated_at
		FROM pii_rules
		WHERE id = $1`

	rule := &PIIRule{}
	err := s.pool.QueryRow(ctx, query, id).Scan(
		&rule.ID, &rule.Name, &rule.Description, &rule.RuleType, &rule.Pattern,
		&rule.Severity, &rule.IsActive, &rule.CreatedAt, &rule.UpdatedAt,
	)

	if err == pgx.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get PII rule: %w", err)
	}

	return rule, nil
}

// ListPIIRules retrieves all PII rules.
func (s *Store) ListPIIRules(ctx context.Context, activeOnly bool) ([]PIIRule, error) {
	query := `
		SELECT id, name, description, rule_type, pattern, severity, is_active, created_at, updated_at
		FROM pii_rules`

	if activeOnly {
		query += ` WHERE is_active = true`
	}
	query += ` ORDER BY severity DESC, name`

	rows, err := s.pool.Query(ctx, query)
	if err != nil {
		return nil, fmt.Errorf("failed to list PII rules: %w", err)
	}
	defer rows.Close()

	rules := []PIIRule{}
	for rows.Next() {
		var r PIIRule
		err := rows.Scan(
			&r.ID, &r.Name, &r.Description, &r.RuleType, &r.Pattern,
			&r.Severity, &r.IsActive, &r.CreatedAt, &r.UpdatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan PII rule: %w", err)
		}
		rules = append(rules, r)
	}

	return rules, nil
}

// UpdatePIIRule updates an existing PII rule.
func (s *Store) UpdatePIIRule(ctx context.Context, id uuid.UUID, req *UpdatePIIRuleRequest) (*PIIRule, error) {
	rule, err := s.GetPIIRule(ctx, id)
	if err != nil {
		return nil, err
	}
	if rule == nil {
		return nil, fmt.Errorf("PII rule not found")
	}

	if req.Name != nil {
		rule.Name = *req.Name
	}
	if req.Description != nil {
		rule.Description = req.Description
	}
	if req.RuleType != nil {
		rule.RuleType = *req.RuleType
	}
	if req.Pattern != nil {
		rule.Pattern = *req.Pattern
	}
	if req.Severity != nil {
		rule.Severity = *req.Severity
	}
	if req.IsActive != nil {
		rule.IsActive = *req.IsActive
	}
	rule.UpdatedAt = time.Now()

	query := `
		UPDATE pii_rules
		SET name = $2, description = $3, rule_type = $4, pattern = $5,
		    severity = $6, is_active = $7, updated_at = $8
		WHERE id = $1`

	_, err = s.pool.Exec(ctx, query,
		id, rule.Name, rule.Description, rule.RuleType, rule.Pattern,
		rule.Severity, rule.IsActive, rule.UpdatedAt,
	)

	if err != nil {
		return nil, fmt.Errorf("failed to update PII rule: %w", err)
	}

	return rule, nil
}

// DeletePIIRule deletes a PII rule by ID.
func (s *Store) DeletePIIRule(ctx context.Context, id uuid.UUID) error {
	query := `DELETE FROM pii_rules WHERE id = $1`
	_, err := s.pool.Exec(ctx, query, id)
	if err != nil {
		return fmt.Errorf("failed to delete PII rule: %w", err)
	}
	return nil
}

// =============================================================================
// AUDIT LOG
// =============================================================================

// CreateAuditLog creates a new audit log entry.
func (s *Store) CreateAuditLog(ctx context.Context, entry *PolicyAuditLog) error {
	entry.ID = uuid.New()
	entry.CreatedAt = time.Now()

	query := `
		INSERT INTO policy_audit_log (id, action, entity_type, entity_id, old_value, new_value,
		                              user_id, user_email, ip_address, user_agent, created_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`

	_, err := s.pool.Exec(ctx, query,
		entry.ID, entry.Action, entry.EntityType, entry.EntityID,
		entry.OldValue, entry.NewValue, entry.UserID, entry.UserEmail,
		entry.IPAddress, entry.UserAgent, entry.CreatedAt,
	)

	if err != nil {
		return fmt.Errorf("failed to create audit log: %w", err)
	}

	return nil
}

// ListAuditLogs retrieves audit logs with filters.
func (s *Store) ListAuditLogs(ctx context.Context, filter *AuditLogFilter) ([]PolicyAuditLog, int, error) {
	baseQuery := `FROM policy_audit_log WHERE 1=1`
	args := []interface{}{}
	argCount := 0

	if filter.EntityType != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND entity_type = $%d", argCount)
		args = append(args, *filter.EntityType)
	}

	if filter.EntityID != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND entity_id = $%d", argCount)
		args = append(args, *filter.EntityID)
	}

	if filter.Action != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND action = $%d", argCount)
		args = append(args, *filter.Action)
	}

	if filter.UserEmail != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND user_email ILIKE $%d", argCount)
		args = append(args, "%"+*filter.UserEmail+"%")
	}

	if filter.FromDate != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND created_at >= $%d", argCount)
		args = append(args, *filter.FromDate)
	}

	if filter.ToDate != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND created_at <= $%d", argCount)
		args = append(args, *filter.ToDate)
	}

	// Count query
	var total int
	countQuery := "SELECT COUNT(*) " + baseQuery
	err := s.pool.QueryRow(ctx, countQuery, args...).Scan(&total)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to count audit logs: %w", err)
	}

	// Data query
	dataQuery := `SELECT id, action, entity_type, entity_id, old_value, new_value,
	              user_id, user_email, ip_address, user_agent, created_at ` + baseQuery +
		` ORDER BY created_at DESC`

	if filter.Limit > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" LIMIT $%d", argCount)
		args = append(args, filter.Limit)
	}
	if filter.Offset > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" OFFSET $%d", argCount)
		args = append(args, filter.Offset)
	}

	rows, err := s.pool.Query(ctx, dataQuery, args...)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list audit logs: %w", err)
	}
	defer rows.Close()

	logs := []PolicyAuditLog{}
	for rows.Next() {
		var l PolicyAuditLog
		err := rows.Scan(
			&l.ID, &l.Action, &l.EntityType, &l.EntityID, &l.OldValue, &l.NewValue,
			&l.UserID, &l.UserEmail, &l.IPAddress, &l.UserAgent, &l.CreatedAt,
		)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to scan audit log: %w", err)
		}
		logs = append(logs, l)
	}

	return logs, total, nil
}

// =============================================================================
// BLOCKED CONTENT LOG
// =============================================================================

// CreateBlockedContentLog creates a new blocked content log entry.
func (s *Store) CreateBlockedContentLog(ctx context.Context, entry *BlockedContentLog) error {
	entry.ID = uuid.New()
	entry.CreatedAt = time.Now()

	query := `
		INSERT INTO blocked_content_log (id, url, domain, block_reason, matched_rule_id, details, created_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7)`

	_, err := s.pool.Exec(ctx, query,
		entry.ID, entry.URL, entry.Domain, entry.BlockReason,
		entry.MatchedRuleID, entry.Details, entry.CreatedAt,
	)

	if err != nil {
		return fmt.Errorf("failed to create blocked content log: %w", err)
	}

	return nil
}

// ListBlockedContent retrieves blocked content logs with filters.
func (s *Store) ListBlockedContent(ctx context.Context, filter *BlockedContentFilter) ([]BlockedContentLog, int, error) {
	baseQuery := `FROM blocked_content_log WHERE 1=1`
	args := []interface{}{}
	argCount := 0

	if filter.Domain != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND domain ILIKE $%d", argCount)
		args = append(args, "%"+*filter.Domain+"%")
	}

	if filter.BlockReason != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND block_reason = $%d", argCount)
		args = append(args, *filter.BlockReason)
	}

	if filter.FromDate != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND created_at >= $%d", argCount)
		args = append(args, *filter.FromDate)
	}

	if filter.ToDate != nil {
		argCount++
		baseQuery += fmt.Sprintf(" AND created_at <= $%d", argCount)
		args = append(args, *filter.ToDate)
	}

	// Count query
	var total int
	countQuery := "SELECT COUNT(*) " + baseQuery
	err := s.pool.QueryRow(ctx, countQuery, args...).Scan(&total)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to count blocked content: %w", err)
	}

	// Data query
	dataQuery := `SELECT id, url, domain, block_reason, matched_rule_id, details, created_at ` + baseQuery +
		` ORDER BY created_at DESC`

	if filter.Limit > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" LIMIT $%d", argCount)
		args = append(args, filter.Limit)
	}
	if filter.Offset > 0 {
		argCount++
		dataQuery += fmt.Sprintf(" OFFSET $%d", argCount)
		args = append(args, filter.Offset)
	}

	rows, err := s.pool.Query(ctx, dataQuery, args...)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list blocked content: %w", err)
	}
	defer rows.Close()

	logs := []BlockedContentLog{}
	for rows.Next() {
		var l BlockedContentLog
		err := rows.Scan(
			&l.ID, &l.URL, &l.Domain, &l.BlockReason,
			&l.MatchedRuleID, &l.Details, &l.CreatedAt,
		)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to scan blocked content: %w", err)
		}
		logs = append(logs, l)
	}

	return logs, total, nil
}

// =============================================================================
// STATISTICS
// =============================================================================

// GetStats retrieves aggregated statistics for the policy system.
func (s *Store) GetStats(ctx context.Context) (*PolicyStats, error) {
	stats := &PolicyStats{
		SourcesByLicense: make(map[string]int),
		BlocksByReason:   make(map[string]int),
	}

	// Active policies
	err := s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM source_policies WHERE is_active = true`).Scan(&stats.ActivePolicies)
	if err != nil {
		return nil, fmt.Errorf("failed to count active policies: %w", err)
	}

	// Total sources
	err = s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM allowed_sources`).Scan(&stats.TotalSources)
	if err != nil {
		return nil, fmt.Errorf("failed to count total sources: %w", err)
	}

	// Active sources
	err = s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM allowed_sources WHERE is_active = true`).Scan(&stats.ActiveSources)
	if err != nil {
		return nil, fmt.Errorf("failed to count active sources: %w", err)
	}

	// Blocked today
	err = s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM blocked_content_log WHERE created_at >= CURRENT_DATE`).Scan(&stats.BlockedToday)
	if err != nil {
		return nil, fmt.Errorf("failed to count blocked today: %w", err)
	}

	// Blocked total
	err = s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM blocked_content_log`).Scan(&stats.BlockedTotal)
	if err != nil {
		return nil, fmt.Errorf("failed to count blocked total: %w", err)
	}

	// Active PII rules
	err = s.pool.QueryRow(ctx, `SELECT COUNT(*) FROM pii_rules WHERE is_active = true`).Scan(&stats.PIIRulesActive)
	if err != nil {
		return nil, fmt.Errorf("failed to count active PII rules: %w", err)
	}

	// Sources by license
	rows, err := s.pool.Query(ctx, `SELECT license, COUNT(*) FROM allowed_sources GROUP BY license`)
	if err != nil {
		return nil, fmt.Errorf("failed to count sources by license: %w", err)
	}
	defer rows.Close()
	for rows.Next() {
		var license string
		var count int
		if err := rows.Scan(&license, &count); err != nil {
			return nil, err
		}
		stats.SourcesByLicense[license] = count
	}

	// Blocks by reason
	rows, err = s.pool.Query(ctx, `SELECT block_reason, COUNT(*) FROM blocked_content_log GROUP BY block_reason`)
	if err != nil {
		return nil, fmt.Errorf("failed to count blocks by reason: %w", err)
	}
	defer rows.Close()
	for rows.Next() {
		var reason string
		var count int
		if err := rows.Scan(&reason, &count); err != nil {
			return nil, err
		}
		stats.BlocksByReason[reason] = count
	}

	// Compliance score (simplified: active sources / total sources)
	if stats.TotalSources > 0 {
		stats.ComplianceScore = float64(stats.ActiveSources) / float64(stats.TotalSources) * 100
	}

	return stats, nil
}

// =============================================================================
// YAML LOADER
// =============================================================================

// LoadFromYAML loads initial policy data from YAML configuration.
func (s *Store) LoadFromYAML(ctx context.Context, config *BundeslaenderConfig) error {
	// Load federal policy
	if config.Federal.Name != "" {
		err := s.loadPolicy(ctx, nil, &config.Federal, &config.DefaultOperations)
		if err != nil {
			return fmt.Errorf("failed to load federal policy: %w", err)
		}
	}

	// Load Bundesland policies
	for code, policyConfig := range config.Bundeslaender {
		if code == "federal" || code == "default_operations" || code == "pii_rules" {
			continue
		}
		bl := Bundesland(code)
		err := s.loadPolicy(ctx, &bl, &policyConfig, &config.DefaultOperations)
		if err != nil {
			return fmt.Errorf("failed to load policy for %s: %w", code, err)
		}
	}

	// Load PII rules
	for _, ruleConfig := range config.PIIRules {
		err := s.loadPIIRule(ctx, &ruleConfig)
		if err != nil {
			return fmt.Errorf("failed to load PII rule %s: %w", ruleConfig.Name, err)
		}
	}

	return nil
}

func (s *Store) loadPolicy(ctx context.Context, bundesland *Bundesland, config *PolicyConfig, ops *OperationsConfig) error {
	// Create policy
	policy, err := s.CreatePolicy(ctx, &CreateSourcePolicyRequest{
		Name:       config.Name,
		Bundesland: bundesland,
	})
	if err != nil {
		return err
	}

	// Create sources
	for _, srcConfig := range config.Sources {
		trustBoost := 0.5
		if srcConfig.TrustBoost > 0 {
			trustBoost = srcConfig.TrustBoost
		}

		var legalBasis, citation *string
		if srcConfig.LegalBasis != "" {
			legalBasis = &srcConfig.LegalBasis
		}
		if srcConfig.CitationTemplate != "" {
			citation = &srcConfig.CitationTemplate
		}

		_, err := s.CreateSource(ctx, &CreateAllowedSourceRequest{
			PolicyID:         policy.ID,
			Domain:           srcConfig.Domain,
			Name:             srcConfig.Name,
			License:          License(srcConfig.License),
			LegalBasis:       legalBasis,
			CitationTemplate: citation,
			TrustBoost:       &trustBoost,
		})
		if err != nil {
			return fmt.Errorf("failed to create source %s: %w", srcConfig.Domain, err)
		}
	}

	return nil
}

func (s *Store) loadPIIRule(ctx context.Context, config *PIIRuleConfig) error {
	severity := PIISeverityBlock
	if config.Severity != "" {
		severity = PIISeverity(config.Severity)
	}

	_, err := s.CreatePIIRule(ctx, &CreatePIIRuleRequest{
		Name:     config.Name,
		RuleType: PIIRuleType(config.Type),
		Pattern:  config.Pattern,
		Severity: severity,
	})

	return err
}

// ToJSON converts an entity to JSON for audit logging.
func ToJSON(v interface{}) json.RawMessage {
	data, _ := json.Marshal(v)
	return data
}
