-- WebDAV Metrics Collection System
-- This migration adds tables for tracking detailed WebDAV sync performance metrics

-- Enum for WebDAV operation types
CREATE TYPE webdav_operation_type AS ENUM (
    'discovery',           -- Directory/file discovery operations
    'download',           -- File download operations
    'metadata_fetch',     -- Getting file metadata (properties)
    'connection_test',    -- Testing connection/authentication
    'validation',         -- Directory validation operations
    'full_sync'           -- Complete sync session
);

-- Enum for WebDAV request types (HTTP methods)
CREATE TYPE webdav_request_type AS ENUM (
    'PROPFIND',
    'GET',
    'HEAD',
    'OPTIONS',
    'POST',
    'PUT',
    'DELETE'
);

-- Table for tracking overall WebDAV sync sessions
CREATE TABLE IF NOT EXISTS webdav_sync_sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    source_id UUID REFERENCES sources(id) ON DELETE CASCADE,
    
    -- Session timing
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    duration_ms BIGINT, -- Total session duration in milliseconds
    
    -- Session scope and configuration
    sync_type TEXT NOT NULL, -- 'full', 'incremental', 'validation', etc.
    root_path TEXT NOT NULL, -- Starting path for the sync
    max_depth INTEGER, -- Maximum directory depth scanned
    
    -- Discovery metrics
    directories_discovered INTEGER NOT NULL DEFAULT 0,
    directories_processed INTEGER NOT NULL DEFAULT 0,
    files_discovered INTEGER NOT NULL DEFAULT 0,
    files_processed INTEGER NOT NULL DEFAULT 0,
    
    -- Size and performance metrics
    total_bytes_discovered BIGINT NOT NULL DEFAULT 0,
    total_bytes_processed BIGINT NOT NULL DEFAULT 0,
    avg_file_size_bytes BIGINT,
    processing_rate_files_per_sec DECIMAL(10,2),
    
    -- Request statistics
    total_http_requests INTEGER NOT NULL DEFAULT 0,
    successful_requests INTEGER NOT NULL DEFAULT 0,
    failed_requests INTEGER NOT NULL DEFAULT 0,
    retry_attempts INTEGER NOT NULL DEFAULT 0,
    
    -- Error handling
    directories_skipped INTEGER NOT NULL DEFAULT 0,
    files_skipped INTEGER NOT NULL DEFAULT 0,
    skip_reasons JSONB, -- JSON object with skip reason counts
    
    -- Final status
    status TEXT NOT NULL DEFAULT 'in_progress', -- 'completed', 'failed', 'cancelled'
    final_error_message TEXT,
    
    -- Performance insights
    slowest_operation_ms BIGINT,
    slowest_operation_path TEXT,
    network_time_ms BIGINT, -- Time spent on network operations
    processing_time_ms BIGINT, -- Time spent on local processing
    
    -- Metadata
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Table for tracking per-directory scan metrics
CREATE TABLE IF NOT EXISTS webdav_directory_metrics (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID NOT NULL REFERENCES webdav_sync_sessions(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    source_id UUID REFERENCES sources(id) ON DELETE CASCADE,
    
    -- Directory identification
    directory_path TEXT NOT NULL,
    directory_depth INTEGER NOT NULL DEFAULT 0,
    parent_directory_path TEXT,
    
    -- Timing metrics
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    scan_duration_ms BIGINT,
    
    -- Discovery results
    files_found INTEGER NOT NULL DEFAULT 0,
    subdirectories_found INTEGER NOT NULL DEFAULT 0,
    total_size_bytes BIGINT NOT NULL DEFAULT 0,
    
    -- Processing results
    files_processed INTEGER NOT NULL DEFAULT 0,
    files_skipped INTEGER NOT NULL DEFAULT 0,
    files_failed INTEGER NOT NULL DEFAULT 0,
    
    -- Request details
    http_requests_made INTEGER NOT NULL DEFAULT 0,
    propfind_requests INTEGER NOT NULL DEFAULT 0,
    get_requests INTEGER NOT NULL DEFAULT 0,
    
    -- Error information
    errors_encountered INTEGER NOT NULL DEFAULT 0,
    error_types JSONB, -- JSON array of error types encountered
    warnings_count INTEGER NOT NULL DEFAULT 0,
    
    -- Performance characteristics
    avg_response_time_ms DECIMAL(10,2),
    slowest_request_ms BIGINT,
    fastest_request_ms BIGINT,
    
    -- ETag and caching
    etag_matches INTEGER NOT NULL DEFAULT 0,
    etag_mismatches INTEGER NOT NULL DEFAULT 0,
    cache_hits INTEGER NOT NULL DEFAULT 0,
    cache_misses INTEGER NOT NULL DEFAULT 0,
    
    -- Final status
    status TEXT NOT NULL DEFAULT 'completed', -- 'completed', 'failed', 'skipped'
    skip_reason TEXT,
    error_message TEXT,
    
    -- Metadata
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Table for tracking individual HTTP request metrics
CREATE TABLE IF NOT EXISTS webdav_request_metrics (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id UUID REFERENCES webdav_sync_sessions(id) ON DELETE CASCADE,
    directory_metric_id UUID REFERENCES webdav_directory_metrics(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    source_id UUID REFERENCES sources(id) ON DELETE CASCADE,
    
    -- Request identification
    request_type webdav_request_type NOT NULL,
    operation_type webdav_operation_type NOT NULL,
    target_path TEXT NOT NULL,
    
    -- Timing
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    duration_ms BIGINT NOT NULL,
    
    -- Request details
    request_size_bytes BIGINT,
    response_size_bytes BIGINT,
    http_status_code INTEGER,
    
    -- Performance metrics
    dns_lookup_ms BIGINT,
    tcp_connect_ms BIGINT,
    tls_handshake_ms BIGINT,
    time_to_first_byte_ms BIGINT,
    
    -- Success/failure tracking
    success BOOLEAN NOT NULL,
    retry_attempt INTEGER NOT NULL DEFAULT 0,
    error_type TEXT,
    error_message TEXT,
    
    -- Server response details
    server_header TEXT,
    dav_header TEXT,
    etag_value TEXT,
    last_modified TIMESTAMPTZ,
    content_type TEXT,
    
    -- Network context
    remote_ip TEXT,
    user_agent TEXT,
    
    -- Metadata
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_user_id ON webdav_sync_sessions(user_id);
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_source_id ON webdav_sync_sessions(source_id);
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_started_at ON webdav_sync_sessions(started_at);
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_status ON webdav_sync_sessions(status);

-- JSON indexes for skip_reasons queries
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_skip_reasons_gin ON webdav_sync_sessions USING gin(skip_reasons);

-- Specific indexes for common skip_reasons queries
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_skip_reasons_keys ON webdav_sync_sessions 
    USING gin((skip_reasons -> 'jsonb_object_keys'));

-- Compound index for user queries with skip_reasons
CREATE INDEX IF NOT EXISTS idx_webdav_sync_sessions_user_skip_reasons ON webdav_sync_sessions(user_id) 
    WHERE skip_reasons IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_session_id ON webdav_directory_metrics(session_id);
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_user_id ON webdav_directory_metrics(user_id);
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_source_id ON webdav_directory_metrics(source_id);
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_path ON webdav_directory_metrics(directory_path);
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_started_at ON webdav_directory_metrics(started_at);

-- JSON indexes for error_types queries
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_error_types_gin ON webdav_directory_metrics USING gin(error_types);

-- Compound index for user queries with error_types
CREATE INDEX IF NOT EXISTS idx_webdav_directory_metrics_user_error_types ON webdav_directory_metrics(user_id) 
    WHERE error_types IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_session_id ON webdav_request_metrics(session_id);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_user_id ON webdav_request_metrics(user_id);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_source_id ON webdav_request_metrics(source_id);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_started_at ON webdav_request_metrics(started_at);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_request_type ON webdav_request_metrics(request_type);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_operation_type ON webdav_request_metrics(operation_type);
CREATE INDEX IF NOT EXISTS idx_webdav_request_metrics_success ON webdav_request_metrics(success);

-- Trigger to automatically update session updated_at timestamp
CREATE OR REPLACE FUNCTION update_webdav_session_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER webdav_sync_sessions_updated_at
    BEFORE UPDATE ON webdav_sync_sessions
    FOR EACH ROW
    EXECUTE FUNCTION update_webdav_session_updated_at();

-- Function to calculate session statistics on completion
CREATE OR REPLACE FUNCTION finalize_webdav_session_metrics(p_session_id UUID)
RETURNS VOID AS $$
DECLARE
    v_session webdav_sync_sessions%ROWTYPE;
    v_total_requests INTEGER;
    v_successful_requests INTEGER;
    v_failed_requests INTEGER;
    v_retry_attempts INTEGER;
    v_network_time_ms BIGINT;
    v_slowest_operation_ms BIGINT;
    v_slowest_operation_path TEXT;
BEGIN
    -- Get current session data
    SELECT * INTO v_session FROM webdav_sync_sessions WHERE id = p_session_id;
    
    IF NOT FOUND THEN
        RETURN;
    END IF;
    
    -- Calculate request statistics from webdav_request_metrics
    SELECT 
        COUNT(*),
        COUNT(*) FILTER (WHERE success = true),
        COUNT(*) FILTER (WHERE success = false),
        COUNT(*) FILTER (WHERE retry_attempt > 0),
        COALESCE(SUM(duration_ms), 0),
        MAX(duration_ms),
        target_path
    INTO 
        v_total_requests,
        v_successful_requests,
        v_failed_requests,
        v_retry_attempts,
        v_network_time_ms,
        v_slowest_operation_ms,
        v_slowest_operation_path
    FROM webdav_request_metrics 
    WHERE session_id = p_session_id
    GROUP BY target_path
    ORDER BY MAX(duration_ms) DESC
    LIMIT 1;
    
    -- Update session with final metrics
    UPDATE webdav_sync_sessions SET
        completed_at = NOW(),
        duration_ms = EXTRACT(EPOCH FROM (NOW() - started_at)) * 1000,
        total_http_requests = COALESCE(v_total_requests, 0),
        successful_requests = COALESCE(v_successful_requests, 0),
        failed_requests = COALESCE(v_failed_requests, 0),
        retry_attempts = COALESCE(v_retry_attempts, 0),
        network_time_ms = COALESCE(v_network_time_ms, 0),
        slowest_operation_ms = v_slowest_operation_ms,
        slowest_operation_path = v_slowest_operation_path,
        processing_rate_files_per_sec = CASE 
            WHEN files_processed > 0 AND EXTRACT(EPOCH FROM (NOW() - started_at)) > 0 
            THEN files_processed / EXTRACT(EPOCH FROM (NOW() - started_at))
            ELSE 0 
        END,
        avg_file_size_bytes = CASE 
            WHEN files_processed > 0 
            THEN total_bytes_processed / files_processed 
            ELSE 0 
        END,
        status = CASE 
            WHEN status = 'in_progress' THEN 'completed'
            ELSE status 
        END,
        updated_at = NOW()
    WHERE id = p_session_id;
END;
$$ LANGUAGE plpgsql;

-- Function to get WebDAV metrics for a specific time period
CREATE OR REPLACE FUNCTION get_webdav_metrics_summary(
    p_user_id UUID DEFAULT NULL,
    p_source_id UUID DEFAULT NULL,
    p_start_time TIMESTAMPTZ DEFAULT NOW() - INTERVAL '24 hours',
    p_end_time TIMESTAMPTZ DEFAULT NOW()
)
RETURNS TABLE (
    total_sessions INTEGER,
    successful_sessions INTEGER,
    failed_sessions INTEGER,
    total_files_processed BIGINT,
    total_bytes_processed BIGINT,
    avg_session_duration_sec DECIMAL,
    avg_processing_rate DECIMAL,
    total_http_requests BIGINT,
    request_success_rate DECIMAL,
    avg_request_duration_ms DECIMAL,
    common_error_types JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        COUNT(*)::INTEGER as total_sessions,
        COUNT(*) FILTER (WHERE s.status = 'completed')::INTEGER as successful_sessions,
        COUNT(*) FILTER (WHERE s.status = 'failed')::INTEGER as failed_sessions,
        COALESCE(SUM(s.files_processed), 0) as total_files_processed,
        COALESCE(SUM(s.total_bytes_processed), 0) as total_bytes_processed,
        COALESCE(AVG(s.duration_ms / 1000.0), 0)::DECIMAL as avg_session_duration_sec,
        COALESCE(AVG(s.processing_rate_files_per_sec), 0)::DECIMAL as avg_processing_rate,
        COALESCE(SUM(s.total_http_requests), 0) as total_http_requests,
        CASE 
            WHEN SUM(s.total_http_requests) > 0 
            THEN (SUM(s.successful_requests)::DECIMAL / SUM(s.total_http_requests) * 100)
            ELSE 0 
        END as request_success_rate,
        COALESCE(
            (SELECT AVG(duration_ms) FROM webdav_request_metrics r 
             WHERE r.started_at BETWEEN p_start_time AND p_end_time
             AND (p_user_id IS NULL OR r.user_id = p_user_id)
             AND (p_source_id IS NULL OR r.source_id = p_source_id)),
            0
        )::DECIMAL as avg_request_duration_ms,
        COALESCE(
            (SELECT jsonb_agg(jsonb_build_object('error_type', error_type, 'count', error_count))
             FROM (
                 SELECT error_type, COUNT(*) as error_count
                 FROM webdav_request_metrics r
                 WHERE r.started_at BETWEEN p_start_time AND p_end_time
                 AND r.success = false
                 AND r.error_type IS NOT NULL
                 AND (p_user_id IS NULL OR r.user_id = p_user_id)
                 AND (p_source_id IS NULL OR r.source_id = p_source_id)
                 GROUP BY error_type
                 ORDER BY error_count DESC
                 LIMIT 10
             ) error_summary),
            '[]'::jsonb
        ) as common_error_types
    FROM webdav_sync_sessions s
    WHERE s.started_at BETWEEN p_start_time AND p_end_time
    AND (p_user_id IS NULL OR s.user_id = p_user_id)
    AND (p_source_id IS NULL OR s.source_id = p_source_id);
END;
$$ LANGUAGE plpgsql;