package ucca

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

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

// AIRegistration represents an EU AI Database registration entry
type AIRegistration struct {
	ID        uuid.UUID `json:"id"`
	TenantID  uuid.UUID `json:"tenant_id"`

	// System
	SystemName        string `json:"system_name"`
	SystemVersion     string `json:"system_version,omitempty"`
	SystemDescription string `json:"system_description,omitempty"`
	IntendedPurpose   string `json:"intended_purpose,omitempty"`

	// Provider
	ProviderName            string `json:"provider_name,omitempty"`
	ProviderLegalForm       string `json:"provider_legal_form,omitempty"`
	ProviderAddress         string `json:"provider_address,omitempty"`
	ProviderCountry         string `json:"provider_country,omitempty"`
	EURepresentativeName    string `json:"eu_representative_name,omitempty"`
	EURepresentativeContact string `json:"eu_representative_contact,omitempty"`

	// Classification
	RiskClassification string `json:"risk_classification"`
	AnnexIIICategory   string `json:"annex_iii_category,omitempty"`
	GPAIClassification string `json:"gpai_classification"`

	// Conformity
	ConformityAssessmentType string `json:"conformity_assessment_type,omitempty"`
	NotifiedBodyName         string `json:"notified_body_name,omitempty"`
	NotifiedBodyID           string `json:"notified_body_id,omitempty"`
	CEMarking                bool   `json:"ce_marking"`

	// Training data
	TrainingDataCategories json.RawMessage `json:"training_data_categories,omitempty"`
	TrainingDataSummary    string          `json:"training_data_summary,omitempty"`

	// Status
	RegistrationStatus string     `json:"registration_status"`
	EUDatabaseID       string     `json:"eu_database_id,omitempty"`
	RegistrationDate   *time.Time `json:"registration_date,omitempty"`
	LastUpdateDate     *time.Time `json:"last_update_date,omitempty"`

	// Links
	UCCAAssessmentID     *uuid.UUID `json:"ucca_assessment_id,omitempty"`
	DecisionTreeResultID *uuid.UUID `json:"decision_tree_result_id,omitempty"`

	// Export
	ExportData json.RawMessage `json:"export_data,omitempty"`

	// Audit
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
	CreatedBy   string    `json:"created_by,omitempty"`
	SubmittedBy string    `json:"submitted_by,omitempty"`
}

// RegistrationStore handles AI registration persistence
type RegistrationStore struct {
	pool *pgxpool.Pool
}

// NewRegistrationStore creates a new registration store
func NewRegistrationStore(pool *pgxpool.Pool) *RegistrationStore {
	return &RegistrationStore{pool: pool}
}

// Create creates a new registration
func (s *RegistrationStore) Create(ctx context.Context, r *AIRegistration) error {
	r.ID = uuid.New()
	r.CreatedAt = time.Now()
	r.UpdatedAt = time.Now()
	if r.RegistrationStatus == "" {
		r.RegistrationStatus = "draft"
	}
	if r.RiskClassification == "" {
		r.RiskClassification = "not_classified"
	}
	if r.GPAIClassification == "" {
		r.GPAIClassification = "none"
	}

	_, err := s.pool.Exec(ctx, `
		INSERT INTO ai_system_registrations (
			id, tenant_id, system_name, system_version, system_description, intended_purpose,
			provider_name, provider_legal_form, provider_address, provider_country,
			eu_representative_name, eu_representative_contact,
			risk_classification, annex_iii_category, gpai_classification,
			conformity_assessment_type, notified_body_name, notified_body_id, ce_marking,
			training_data_categories, training_data_summary,
			registration_status, ucca_assessment_id, decision_tree_result_id,
			created_by
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12,
			$13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25
		)`,
		r.ID, r.TenantID, r.SystemName, r.SystemVersion, r.SystemDescription, r.IntendedPurpose,
		r.ProviderName, r.ProviderLegalForm, r.ProviderAddress, r.ProviderCountry,
		r.EURepresentativeName, r.EURepresentativeContact,
		r.RiskClassification, r.AnnexIIICategory, r.GPAIClassification,
		r.ConformityAssessmentType, r.NotifiedBodyName, r.NotifiedBodyID, r.CEMarking,
		r.TrainingDataCategories, r.TrainingDataSummary,
		r.RegistrationStatus, r.UCCAAssessmentID, r.DecisionTreeResultID,
		r.CreatedBy,
	)
	return err
}

// List returns all registrations for a tenant
func (s *RegistrationStore) List(ctx context.Context, tenantID uuid.UUID) ([]AIRegistration, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT id, tenant_id, system_name, system_version, system_description, intended_purpose,
			provider_name, provider_legal_form, provider_address, provider_country,
			eu_representative_name, eu_representative_contact,
			risk_classification, annex_iii_category, gpai_classification,
			conformity_assessment_type, notified_body_name, notified_body_id, ce_marking,
			training_data_categories, training_data_summary,
			registration_status, eu_database_id, registration_date, last_update_date,
			ucca_assessment_id, decision_tree_result_id, export_data,
			created_at, updated_at, created_by, submitted_by
		FROM ai_system_registrations
		WHERE tenant_id = $1
		ORDER BY created_at DESC`,
		tenantID,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var registrations []AIRegistration
	for rows.Next() {
		var r AIRegistration
		err := rows.Scan(
			&r.ID, &r.TenantID, &r.SystemName, &r.SystemVersion, &r.SystemDescription, &r.IntendedPurpose,
			&r.ProviderName, &r.ProviderLegalForm, &r.ProviderAddress, &r.ProviderCountry,
			&r.EURepresentativeName, &r.EURepresentativeContact,
			&r.RiskClassification, &r.AnnexIIICategory, &r.GPAIClassification,
			&r.ConformityAssessmentType, &r.NotifiedBodyName, &r.NotifiedBodyID, &r.CEMarking,
			&r.TrainingDataCategories, &r.TrainingDataSummary,
			&r.RegistrationStatus, &r.EUDatabaseID, &r.RegistrationDate, &r.LastUpdateDate,
			&r.UCCAAssessmentID, &r.DecisionTreeResultID, &r.ExportData,
			&r.CreatedAt, &r.UpdatedAt, &r.CreatedBy, &r.SubmittedBy,
		)
		if err != nil {
			return nil, err
		}
		registrations = append(registrations, r)
	}
	return registrations, nil
}

// GetByID returns a registration by ID
func (s *RegistrationStore) GetByID(ctx context.Context, id uuid.UUID) (*AIRegistration, error) {
	var r AIRegistration
	err := s.pool.QueryRow(ctx, `
		SELECT id, tenant_id, system_name, system_version, system_description, intended_purpose,
			provider_name, provider_legal_form, provider_address, provider_country,
			eu_representative_name, eu_representative_contact,
			risk_classification, annex_iii_category, gpai_classification,
			conformity_assessment_type, notified_body_name, notified_body_id, ce_marking,
			training_data_categories, training_data_summary,
			registration_status, eu_database_id, registration_date, last_update_date,
			ucca_assessment_id, decision_tree_result_id, export_data,
			created_at, updated_at, created_by, submitted_by
		FROM ai_system_registrations
		WHERE id = $1`,
		id,
	).Scan(
		&r.ID, &r.TenantID, &r.SystemName, &r.SystemVersion, &r.SystemDescription, &r.IntendedPurpose,
		&r.ProviderName, &r.ProviderLegalForm, &r.ProviderAddress, &r.ProviderCountry,
		&r.EURepresentativeName, &r.EURepresentativeContact,
		&r.RiskClassification, &r.AnnexIIICategory, &r.GPAIClassification,
		&r.ConformityAssessmentType, &r.NotifiedBodyName, &r.NotifiedBodyID, &r.CEMarking,
		&r.TrainingDataCategories, &r.TrainingDataSummary,
		&r.RegistrationStatus, &r.EUDatabaseID, &r.RegistrationDate, &r.LastUpdateDate,
		&r.UCCAAssessmentID, &r.DecisionTreeResultID, &r.ExportData,
		&r.CreatedAt, &r.UpdatedAt, &r.CreatedBy, &r.SubmittedBy,
	)
	if err != nil {
		return nil, err
	}
	return &r, nil
}

// Update updates a registration
func (s *RegistrationStore) Update(ctx context.Context, r *AIRegistration) error {
	r.UpdatedAt = time.Now()
	_, err := s.pool.Exec(ctx, `
		UPDATE ai_system_registrations SET
			system_name = $2, system_version = $3, system_description = $4, intended_purpose = $5,
			provider_name = $6, provider_legal_form = $7, provider_address = $8, provider_country = $9,
			eu_representative_name = $10, eu_representative_contact = $11,
			risk_classification = $12, annex_iii_category = $13, gpai_classification = $14,
			conformity_assessment_type = $15, notified_body_name = $16, notified_body_id = $17, ce_marking = $18,
			training_data_categories = $19, training_data_summary = $20,
			registration_status = $21, eu_database_id = $22,
			export_data = $23, updated_at = $24, submitted_by = $25
		WHERE id = $1`,
		r.ID, r.SystemName, r.SystemVersion, r.SystemDescription, r.IntendedPurpose,
		r.ProviderName, r.ProviderLegalForm, r.ProviderAddress, r.ProviderCountry,
		r.EURepresentativeName, r.EURepresentativeContact,
		r.RiskClassification, r.AnnexIIICategory, r.GPAIClassification,
		r.ConformityAssessmentType, r.NotifiedBodyName, r.NotifiedBodyID, r.CEMarking,
		r.TrainingDataCategories, r.TrainingDataSummary,
		r.RegistrationStatus, r.EUDatabaseID,
		r.ExportData, r.UpdatedAt, r.SubmittedBy,
	)
	return err
}

// UpdateStatus changes only the registration status
func (s *RegistrationStore) UpdateStatus(ctx context.Context, id uuid.UUID, status string, submittedBy string) error {
	now := time.Now()
	_, err := s.pool.Exec(ctx, `
		UPDATE ai_system_registrations
		SET registration_status = $2, submitted_by = $3, updated_at = $4,
			registration_date = CASE WHEN $2 = 'submitted' THEN $4 ELSE registration_date END,
			last_update_date = $4
		WHERE id = $1`,
		id, status, submittedBy, now,
	)
	return err
}

// BuildExportJSON creates the EU AI Database submission JSON
func (s *RegistrationStore) BuildExportJSON(r *AIRegistration) json.RawMessage {
	export := map[string]interface{}{
		"schema_version": "1.0",
		"submission_type": "ai_system_registration",
		"regulation": "EU AI Act (EU) 2024/1689",
		"article": "Art. 49",
		"provider": map[string]interface{}{
			"name":               r.ProviderName,
			"legal_form":         r.ProviderLegalForm,
			"address":            r.ProviderAddress,
			"country":            r.ProviderCountry,
			"eu_representative":  r.EURepresentativeName,
			"eu_rep_contact":     r.EURepresentativeContact,
		},
		"system": map[string]interface{}{
			"name":        r.SystemName,
			"version":     r.SystemVersion,
			"description": r.SystemDescription,
			"purpose":     r.IntendedPurpose,
		},
		"classification": map[string]interface{}{
			"risk_level":         r.RiskClassification,
			"annex_iii_category": r.AnnexIIICategory,
			"gpai":               r.GPAIClassification,
		},
		"conformity": map[string]interface{}{
			"assessment_type": r.ConformityAssessmentType,
			"notified_body":   r.NotifiedBodyName,
			"notified_body_id": r.NotifiedBodyID,
			"ce_marking":      r.CEMarking,
		},
		"training_data": map[string]interface{}{
			"categories": r.TrainingDataCategories,
			"summary":    r.TrainingDataSummary,
		},
		"status": r.RegistrationStatus,
	}
	data, _ := json.Marshal(export)
	return data
}
