-- SurrealDB Schema for Task Orchestrator
-- This schema defines all tables, indexes, and constraints for the task management system

-- =============================================================================
-- DEFINE NAMESPACE AND DATABASE
-- =============================================================================

-- Switch to task orchestrator namespace and database
USE NS orchestrator DB tasks;

-- =============================================================================
-- USER AUTHENTICATION AND PERMISSIONS
-- =============================================================================

-- Define scopes for authentication
DEFINE SCOPE user SESSION 24h
    SIGNUP ( CREATE user SET email = $email, pass = crypto::argon2::generate($pass), created_at = time::now() )
    SIGNIN ( SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(pass, $pass) );

-- Define users table for authentication and RBAC
DEFINE TABLE users SCHEMAFULL
    PERMISSIONS
        FOR select, update WHERE id = $auth.id
        FOR create, delete WHERE $auth.role = "admin";

DEFINE FIELD id ON TABLE users TYPE record<users>;
DEFINE FIELD email ON TABLE users TYPE string;
DEFINE FIELD pass ON TABLE users TYPE string;
DEFINE FIELD role ON TABLE users TYPE string DEFAULT "user";
DEFINE FIELD permissions ON TABLE users TYPE array<string> DEFAULT [];
DEFINE FIELD created_at ON TABLE users TYPE datetime;
DEFINE FIELD updated_at ON TABLE users TYPE datetime DEFAULT time::now();
DEFINE FIELD last_login ON TABLE users TYPE datetime;
DEFINE FIELD active ON TABLE users TYPE bool DEFAULT true;

-- Indexes for users
DEFINE INDEX users_email_idx ON TABLE users COLUMNS email UNIQUE;
DEFINE INDEX users_role_idx ON TABLE users COLUMNS role;

-- =============================================================================
-- TASK MANAGEMENT TABLES
-- =============================================================================

-- Main tasks table
DEFINE TABLE tasks SCHEMAFULL
    PERMISSIONS
        FOR select WHERE $auth.role = "admin" OR $auth.role = "user"
        FOR create, update, delete WHERE $auth.role = "admin" OR created_by = $auth.id;

DEFINE FIELD id ON TABLE tasks TYPE record<tasks>;
DEFINE FIELD name ON TABLE tasks TYPE string;
DEFINE FIELD command ON TABLE tasks TYPE string;
DEFINE FIELD args ON TABLE tasks TYPE array<string> DEFAULT [];
DEFINE FIELD dependencies ON TABLE tasks TYPE array<string> DEFAULT [];
DEFINE FIELD status ON TABLE tasks TYPE string DEFAULT "Pending"
    ASSERT $value IN ["Pending", "Running", "Completed", "Failed", "Cancelled"];
DEFINE FIELD priority ON TABLE tasks TYPE int DEFAULT 0;
DEFINE FIELD created_at ON TABLE tasks TYPE datetime DEFAULT time::now();
DEFINE FIELD updated_at ON TABLE tasks TYPE datetime DEFAULT time::now();
DEFINE FIELD started_at ON TABLE tasks TYPE datetime;
DEFINE FIELD completed_at ON TABLE tasks TYPE datetime;
DEFINE FIELD output ON TABLE tasks TYPE string;
DEFINE FIELD error ON TABLE tasks TYPE string;
DEFINE FIELD created_by ON TABLE tasks TYPE record<users>;
DEFINE FIELD metadata ON TABLE tasks TYPE object DEFAULT {};
DEFINE FIELD retry_count ON TABLE tasks TYPE int DEFAULT 0;
DEFINE FIELD max_retries ON TABLE tasks TYPE int DEFAULT 3;

-- Indexes for tasks
DEFINE INDEX tasks_status_idx ON TABLE tasks COLUMNS status;
DEFINE INDEX tasks_priority_idx ON TABLE tasks COLUMNS priority;
DEFINE INDEX tasks_created_at_idx ON TABLE tasks COLUMNS created_at;
DEFINE INDEX tasks_name_idx ON TABLE tasks COLUMNS name;
DEFINE INDEX tasks_status_priority_idx ON TABLE tasks COLUMNS status, priority;

-- Task queue table for priority-based scheduling
DEFINE TABLE task_queue SCHEMAFULL
    PERMISSIONS
        FOR select, create, update, delete WHERE $auth.role = "admin" OR $auth.role = "user";

DEFINE FIELD id ON TABLE task_queue TYPE record<task_queue>;
DEFINE FIELD task_id ON TABLE task_queue TYPE record<tasks>;
DEFINE FIELD priority ON TABLE task_queue TYPE int DEFAULT 0;
DEFINE FIELD enqueued_at ON TABLE task_queue TYPE datetime DEFAULT time::now();
DEFINE FIELD processing_started ON TABLE task_queue TYPE datetime;
DEFINE FIELD worker_id ON TABLE task_queue TYPE string;

-- Indexes for task queue
DEFINE INDEX queue_priority_idx ON TABLE task_queue COLUMNS priority DESC, enqueued_at ASC;
DEFINE INDEX queue_task_id_idx ON TABLE task_queue COLUMNS task_id UNIQUE;

-- =============================================================================
-- TASK DEPENDENCIES (GRAPH RELATIONSHIPS)
-- =============================================================================

-- Task dependency relationships using SurrealDB's graph capabilities
DEFINE TABLE depends_on SCHEMAFULL TYPE RELATION IN tasks OUT tasks
    PERMISSIONS
        FOR select, create, update, delete WHERE $auth.role = "admin" OR $auth.role = "user";

DEFINE FIELD created_at ON TABLE depends_on TYPE datetime DEFAULT time::now();
DEFINE FIELD dependency_type ON TABLE depends_on TYPE string DEFAULT "hard";
DEFINE FIELD created_by ON TABLE depends_on TYPE record<users>;

-- =============================================================================
-- AUDIT LOGGING
-- =============================================================================

-- Audit log table for tracking all operations
DEFINE TABLE audit_log SCHEMAFULL
    PERMISSIONS
        FOR select WHERE $auth.role = "admin"
        FOR create WHERE $auth.role = "admin" OR $auth.role = "user";

DEFINE FIELD id ON TABLE audit_log TYPE record<audit_log>;
DEFINE FIELD task_id ON TABLE audit_log TYPE string;
DEFINE FIELD operation ON TABLE audit_log TYPE string;
DEFINE FIELD old_status ON TABLE audit_log TYPE string;
DEFINE FIELD new_status ON TABLE audit_log TYPE string;
DEFINE FIELD user_id ON TABLE audit_log TYPE record<users>;
DEFINE FIELD timestamp ON TABLE audit_log TYPE datetime DEFAULT time::now();
DEFINE FIELD metadata ON TABLE audit_log TYPE object DEFAULT {};
DEFINE FIELD ip_address ON TABLE audit_log TYPE string;
DEFINE FIELD user_agent ON TABLE audit_log TYPE string;

-- Indexes for audit log
DEFINE INDEX audit_task_id_idx ON TABLE audit_log COLUMNS task_id;
DEFINE INDEX audit_timestamp_idx ON TABLE audit_log COLUMNS timestamp;
DEFINE INDEX audit_user_id_idx ON TABLE audit_log COLUMNS user_id;
DEFINE INDEX audit_operation_idx ON TABLE audit_log COLUMNS operation;

-- =============================================================================
-- METRICS AND MONITORING
-- =============================================================================

-- Metrics table for time-series data
DEFINE TABLE metrics SCHEMAFULL
    PERMISSIONS
        FOR select WHERE $auth.role = "admin" OR $auth.role = "user"
        FOR create WHERE $auth.role = "admin" OR $auth.role = "system";

DEFINE FIELD id ON TABLE metrics TYPE record<metrics>;
DEFINE FIELD name ON TABLE metrics TYPE string;
DEFINE FIELD value ON TABLE metrics TYPE float;
DEFINE FIELD tags ON TABLE metrics TYPE object DEFAULT {};
DEFINE FIELD timestamp ON TABLE metrics TYPE datetime DEFAULT time::now();
DEFINE FIELD source ON TABLE metrics TYPE string DEFAULT "orchestrator";

-- Indexes for metrics (optimized for time-series queries)
DEFINE INDEX metrics_name_timestamp_idx ON TABLE metrics COLUMNS name, timestamp;
DEFINE INDEX metrics_timestamp_idx ON TABLE metrics COLUMNS timestamp;
DEFINE INDEX metrics_name_idx ON TABLE metrics COLUMNS name;

-- =============================================================================
-- REAL-TIME EVENTS
-- =============================================================================

-- Events table for real-time notifications
DEFINE TABLE task_events SCHEMAFULL
    PERMISSIONS
        FOR select WHERE $auth.role = "admin" OR $auth.role = "user"
        FOR create WHERE $auth.role = "admin" OR $auth.role = "system";

DEFINE FIELD id ON TABLE task_events TYPE record<task_events>;
DEFINE FIELD event_type ON TABLE task_events TYPE string
    ASSERT $value IN ["Created", "StatusChanged", "Updated", "Deleted", "Enqueued", "Dequeued", "Completed", "Failed"];
DEFINE FIELD task_id ON TABLE task_events TYPE string;
DEFINE FIELD timestamp ON TABLE task_events TYPE datetime DEFAULT time::now();
DEFINE FIELD metadata ON TABLE task_events TYPE object DEFAULT {};
DEFINE FIELD user_id ON TABLE task_events TYPE record<users>;

-- Indexes for events
DEFINE INDEX events_timestamp_idx ON TABLE task_events COLUMNS timestamp;
DEFINE INDEX events_task_id_idx ON TABLE task_events COLUMNS task_id;
DEFINE INDEX events_type_idx ON TABLE task_events COLUMNS event_type;

-- =============================================================================
-- SYSTEM CONFIGURATION
-- =============================================================================

-- System configuration table
DEFINE TABLE system_config SCHEMAFULL
    PERMISSIONS
        FOR select WHERE $auth.role = "admin" OR $auth.role = "user"
        FOR create, update, delete WHERE $auth.role = "admin";

DEFINE FIELD key ON TABLE system_config TYPE string;
DEFINE FIELD value ON TABLE system_config TYPE string;
DEFINE FIELD description ON TABLE system_config TYPE string;
DEFINE FIELD updated_at ON TABLE system_config TYPE datetime DEFAULT time::now();
DEFINE FIELD updated_by ON TABLE system_config TYPE record<users>;

-- Unique index for config keys
DEFINE INDEX config_key_idx ON TABLE system_config COLUMNS key UNIQUE;

-- =============================================================================
-- EVENT TRIGGERS FOR AUDIT LOGGING
-- =============================================================================

-- Trigger to automatically create audit entries when tasks are updated
DEFINE EVENT task_status_change ON TABLE tasks WHEN $event = "UPDATE" AND $before.status != $after.status THEN {
    CREATE audit_log SET
        task_id = $after.id,
        operation = "status_change",
        old_status = $before.status,
        new_status = $after.status,
        user_id = $auth.id,
        timestamp = time::now(),
        metadata = {
            "old_status": $before.status,
            "new_status": $after.status,
            "task_name": $after.name
        };

    -- Also create a task event for real-time notifications
    CREATE task_events SET
        event_type = "StatusChanged",
        task_id = string::concat("tasks:", $after.id),
        timestamp = time::now(),
        metadata = {
            "old_status": $before.status,
            "new_status": $after.status,
            "task_name": $after.name
        },
        user_id = $auth.id;
};

-- Trigger for task creation
DEFINE EVENT task_created ON TABLE tasks WHEN $event = "CREATE" THEN {
    CREATE audit_log SET
        task_id = $after.id,
        operation = "created",
        new_status = $after.status,
        user_id = $auth.id,
        timestamp = time::now(),
        metadata = {
            "task_name": $after.name,
            "command": $after.command
        };

    -- Create task event
    CREATE task_events SET
        event_type = "Created",
        task_id = string::concat("tasks:", $after.id),
        timestamp = time::now(),
        metadata = {
            "task_name": $after.name,
            "status": $after.status
        },
        user_id = $auth.id;
};

-- Trigger for task deletion
DEFINE EVENT task_deleted ON TABLE tasks WHEN $event = "DELETE" THEN {
    CREATE audit_log SET
        task_id = $before.id,
        operation = "deleted",
        old_status = $before.status,
        user_id = $auth.id,
        timestamp = time::now(),
        metadata = {
            "task_name": $before.name
        };

    -- Create task event
    CREATE task_events SET
        event_type = "Deleted",
        task_id = string::concat("tasks:", $before.id),
        timestamp = time::now(),
        metadata = {
            "task_name": $before.name,
            "status": $before.status
        },
        user_id = $auth.id;
};

-- =============================================================================
-- INITIAL DATA AND CONFIGURATION
-- =============================================================================

-- Create default admin user
CREATE user:admin SET
    email = "admin@orchestrator.local",
    pass = crypto::argon2::generate("admin123"),
    role = "admin",
    permissions = ["task:create", "task:read", "task:update", "task:delete", "user:manage", "system:config"],
    created_at = time::now(),
    active = true;

-- Create default system configuration
CREATE system_config:max_concurrent_tasks SET
    key = "max_concurrent_tasks",
    value = "10",
    description = "Maximum number of tasks that can run concurrently",
    updated_at = time::now(),
    updated_by = user:admin;

CREATE system_config:task_timeout SET
    key = "task_timeout_seconds",
    value = "3600",
    description = "Default timeout for tasks in seconds",
    updated_at = time::now(),
    updated_by = user:admin;

CREATE system_config:cleanup_interval SET
    key = "cleanup_interval_hours",
    value = "24",
    description = "Interval for cleaning up completed tasks in hours",
    updated_at = time::now(),
    updated_by = user:admin;

-- =============================================================================
-- ANALYTICS AND REPORTING VIEWS
-- =============================================================================

-- View for task statistics
-- Note: SurrealDB doesn't have traditional views, but we can create functions

-- Function to get task statistics
DEFINE FUNCTION fn::get_task_statistics() {
    LET $total = (SELECT count() FROM tasks GROUP ALL)[0].count;
    LET $pending = (SELECT count() FROM tasks WHERE status = "Pending" GROUP ALL)[0].count;
    LET $running = (SELECT count() FROM tasks WHERE status = "Running" GROUP ALL)[0].count;
    LET $completed = (SELECT count() FROM tasks WHERE status = "Completed" GROUP ALL)[0].count;
    LET $failed = (SELECT count() FROM tasks WHERE status = "Failed" GROUP ALL)[0].count;

    RETURN {
        total_tasks: $total OR 0,
        pending_tasks: $pending OR 0,
        running_tasks: $running OR 0,
        completed_tasks: $completed OR 0,
        failed_tasks: $failed OR 0,
        last_updated: time::now()
    };
};

-- Function to get queue statistics
DEFINE FUNCTION fn::get_queue_statistics() {
    LET $queue_size = (SELECT count() FROM task_queue GROUP ALL)[0].count;
    LET $avg_wait_time = (SELECT math::mean(processing_started - enqueued_at) AS avg_wait FROM task_queue WHERE processing_started IS NOT NONE GROUP ALL)[0].avg_wait;

    RETURN {
        queue_size: $queue_size OR 0,
        avg_wait_time_seconds: $avg_wait_time OR 0,
        last_updated: time::now()
    };
};

-- =============================================================================
-- CLEANUP PROCEDURES
-- =============================================================================

-- Function to cleanup old completed tasks
DEFINE FUNCTION fn::cleanup_completed_tasks($older_than_hours: number) {
    LET $cutoff_time = time::now() - duration::from::hours($older_than_hours);
    LET $deleted_tasks = DELETE tasks WHERE status = "Completed" AND completed_at < $cutoff_time;

    -- Log cleanup operation
    CREATE audit_log SET
        task_id = "system",
        operation = "cleanup_completed_tasks",
        timestamp = time::now(),
        metadata = {
            "deleted_count": array::len($deleted_tasks),
            "cutoff_time": $cutoff_time
        };

    RETURN array::len($deleted_tasks);
};

-- Function to cleanup old audit logs
DEFINE FUNCTION fn::cleanup_audit_logs($older_than_days: number) {
    LET $cutoff_time = time::now() - duration::from::days($older_than_days);
    LET $deleted_logs = DELETE audit_log WHERE timestamp < $cutoff_time;

    RETURN array::len($deleted_logs);
};

-- Function to cleanup old metrics
DEFINE FUNCTION fn::cleanup_metrics($older_than_days: number) {
    LET $cutoff_time = time::now() - duration::from::days($older_than_days);
    LET $deleted_metrics = DELETE metrics WHERE timestamp < $cutoff_time;

    RETURN array::len($deleted_metrics);
};
