package ucca

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

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

// ObligationsStore handles persistence of obligations assessments
type ObligationsStore struct {
	pool *pgxpool.Pool
}

// NewObligationsStore creates a new ObligationsStore
func NewObligationsStore(pool *pgxpool.Pool) *ObligationsStore {
	return &ObligationsStore{pool: pool}
}

// CreateAssessment persists a new obligations assessment
func (s *ObligationsStore) CreateAssessment(ctx context.Context, a *ObligationsAssessment) error {
	if a.ID == uuid.Nil {
		a.ID = uuid.New()
	}
	a.CreatedAt = time.Now().UTC()
	a.UpdatedAt = a.CreatedAt

	// Marshal JSON fields
	factsJSON, err := json.Marshal(a.Facts)
	if err != nil {
		return fmt.Errorf("failed to marshal facts: %w", err)
	}

	overviewJSON, err := json.Marshal(a.Overview)
	if err != nil {
		return fmt.Errorf("failed to marshal overview: %w", err)
	}

	_, err = s.pool.Exec(ctx, `
		INSERT INTO obligations_assessments (
			id, tenant_id, organization_name, facts, overview,
			status, created_at, updated_at, created_by
		) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
	`,
		a.ID, a.TenantID, a.OrganizationName, factsJSON, overviewJSON,
		a.Status, a.CreatedAt, a.UpdatedAt, a.CreatedBy,
	)

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

	return nil
}

// GetAssessment retrieves an assessment by ID
func (s *ObligationsStore) GetAssessment(ctx context.Context, tenantID, assessmentID uuid.UUID) (*ObligationsAssessment, error) {
	var a ObligationsAssessment
	var factsJSON, overviewJSON []byte

	err := s.pool.QueryRow(ctx, `
		SELECT id, tenant_id, organization_name, facts, overview,
			   status, created_at, updated_at, created_by
		FROM obligations_assessments
		WHERE id = $1 AND tenant_id = $2
	`, assessmentID, tenantID).Scan(
		&a.ID, &a.TenantID, &a.OrganizationName, &factsJSON, &overviewJSON,
		&a.Status, &a.CreatedAt, &a.UpdatedAt, &a.CreatedBy,
	)

	if err != nil {
		return nil, fmt.Errorf("assessment not found: %w", err)
	}

	// Unmarshal JSON fields
	if err := json.Unmarshal(factsJSON, &a.Facts); err != nil {
		return nil, fmt.Errorf("failed to unmarshal facts: %w", err)
	}
	if err := json.Unmarshal(overviewJSON, &a.Overview); err != nil {
		return nil, fmt.Errorf("failed to unmarshal overview: %w", err)
	}

	return &a, nil
}

// ListAssessments returns all assessments for a tenant
func (s *ObligationsStore) ListAssessments(ctx context.Context, tenantID uuid.UUID, limit, offset int) ([]*ObligationsAssessment, error) {
	if limit <= 0 {
		limit = 20
	}
	if limit > 100 {
		limit = 100
	}

	rows, err := s.pool.Query(ctx, `
		SELECT id, tenant_id, organization_name, facts, overview,
			   status, created_at, updated_at, created_by
		FROM obligations_assessments
		WHERE tenant_id = $1
		ORDER BY created_at DESC
		LIMIT $2 OFFSET $3
	`, tenantID, limit, offset)

	if err != nil {
		return nil, fmt.Errorf("failed to query assessments: %w", err)
	}
	defer rows.Close()

	var assessments []*ObligationsAssessment
	for rows.Next() {
		var a ObligationsAssessment
		var factsJSON, overviewJSON []byte

		if err := rows.Scan(
			&a.ID, &a.TenantID, &a.OrganizationName, &factsJSON, &overviewJSON,
			&a.Status, &a.CreatedAt, &a.UpdatedAt, &a.CreatedBy,
		); err != nil {
			return nil, fmt.Errorf("failed to scan row: %w", err)
		}

		if err := json.Unmarshal(factsJSON, &a.Facts); err != nil {
			return nil, fmt.Errorf("failed to unmarshal facts: %w", err)
		}
		if err := json.Unmarshal(overviewJSON, &a.Overview); err != nil {
			return nil, fmt.Errorf("failed to unmarshal overview: %w", err)
		}

		assessments = append(assessments, &a)
	}

	return assessments, nil
}

// UpdateAssessment updates an existing assessment
func (s *ObligationsStore) UpdateAssessment(ctx context.Context, a *ObligationsAssessment) error {
	a.UpdatedAt = time.Now().UTC()

	factsJSON, err := json.Marshal(a.Facts)
	if err != nil {
		return fmt.Errorf("failed to marshal facts: %w", err)
	}

	overviewJSON, err := json.Marshal(a.Overview)
	if err != nil {
		return fmt.Errorf("failed to marshal overview: %w", err)
	}

	result, err := s.pool.Exec(ctx, `
		UPDATE obligations_assessments
		SET organization_name = $3, facts = $4, overview = $5,
			status = $6, updated_at = $7
		WHERE id = $1 AND tenant_id = $2
	`,
		a.ID, a.TenantID, a.OrganizationName, factsJSON, overviewJSON,
		a.Status, a.UpdatedAt,
	)

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

	if result.RowsAffected() == 0 {
		return fmt.Errorf("assessment not found")
	}

	return nil
}

// DeleteAssessment deletes an assessment
func (s *ObligationsStore) DeleteAssessment(ctx context.Context, tenantID, assessmentID uuid.UUID) error {
	result, err := s.pool.Exec(ctx, `
		DELETE FROM obligations_assessments
		WHERE id = $1 AND tenant_id = $2
	`, assessmentID, tenantID)

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

	if result.RowsAffected() == 0 {
		return fmt.Errorf("assessment not found")
	}

	return nil
}

// GetMigrationSQL returns the SQL to create the required table
func (s *ObligationsStore) GetMigrationSQL() string {
	return `
-- Obligations Assessments Table
CREATE TABLE IF NOT EXISTS obligations_assessments (
    id UUID PRIMARY KEY,
    tenant_id UUID NOT NULL,
    organization_name VARCHAR(255),
    facts JSONB NOT NULL,
    overview JSONB NOT NULL,
    status VARCHAR(50) NOT NULL DEFAULT 'completed',
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    created_by UUID,

    CONSTRAINT fk_tenant FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);

-- Indexes
CREATE INDEX IF NOT EXISTS idx_obligations_assessments_tenant ON obligations_assessments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_obligations_assessments_created ON obligations_assessments(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_obligations_assessments_status ON obligations_assessments(status);

-- GIN index for JSON queries
CREATE INDEX IF NOT EXISTS idx_obligations_assessments_overview ON obligations_assessments USING GIN (overview);
`
}
