-- Migration 015: Git Diff Storage System
-- This migration adds tables for storing git diffs with size-based storage strategy

-- Store actual diff content with size-based strategy
CREATE TABLE IF NOT EXISTS diff_contents (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  commit_id UUID REFERENCES repository_commit_details(id) ON DELETE CASCADE,
  file_change_id UUID REFERENCES repository_commit_files(id) ON DELETE CASCADE,
  
  -- Diff metadata
  diff_header TEXT, -- "diff --git a/file.py b/file.py"
  diff_size_bytes INTEGER NOT NULL,
  
  -- Storage strategy based on size
  storage_type VARCHAR(20) NOT NULL, -- 'external' (all diffs stored on disk)
  
  -- Store reference only (path on disk)
  external_storage_path TEXT NOT NULL,
  external_storage_provider VARCHAR(50) DEFAULT 'local', -- 'local', 's3', 'gcs'
  
  -- File information
  file_path TEXT NOT NULL,
  change_type VARCHAR(20) NOT NULL, -- 'added', 'modified', 'deleted', 'renamed'
  
  -- Processing status
  processing_status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'processed', 'failed'
  processing_error TEXT,
  
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Diff Processing Queue (for background processing)
CREATE TABLE IF NOT EXISTS diff_processing_queue (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  commit_id UUID REFERENCES repository_commit_details(id) ON DELETE CASCADE,
  repository_id UUID REFERENCES all_repositories(id) ON DELETE CASCADE,
  
  -- Processing metadata
  queue_status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'processing', 'completed', 'failed'
  priority INTEGER DEFAULT 0, -- Higher number = higher priority
  retry_count INTEGER DEFAULT 0,
  max_retries INTEGER DEFAULT 3,
  
  -- Git diff parameters
  from_sha VARCHAR(64),
  to_sha VARCHAR(64),
  repo_local_path TEXT NOT NULL,
  
  -- Processing results
  processed_at TIMESTAMP,
  error_message TEXT,
  
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Diff Statistics (for monitoring and optimization)
CREATE TABLE IF NOT EXISTS diff_statistics (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  repository_id UUID REFERENCES all_repositories(id) ON DELETE CASCADE,
  
  -- Statistics period
  period_start TIMESTAMP NOT NULL,
  period_end TIMESTAMP NOT NULL,
  
  -- Count statistics
  total_commits INTEGER DEFAULT 0,
  total_files_changed INTEGER DEFAULT 0,
  total_diffs_processed INTEGER DEFAULT 0,
  
  -- Size statistics
  total_diff_size_bytes BIGINT DEFAULT 0,
  avg_diff_size_bytes DECIMAL(10,2) DEFAULT 0,
  max_diff_size_bytes BIGINT DEFAULT 0,
  
  -- Storage type breakdown
  diffs_stored_external INTEGER DEFAULT 0,
  
  -- Performance metrics
  avg_processing_time_ms DECIMAL(10,2) DEFAULT 0,
  failed_processing_count INTEGER DEFAULT 0,
  
  created_at TIMESTAMP DEFAULT NOW()
);

-- Indexes for Performance
CREATE INDEX IF NOT EXISTS idx_diff_contents_commit_id ON diff_contents(commit_id);
CREATE INDEX IF NOT EXISTS idx_diff_contents_file_change_id ON diff_contents(file_change_id);
CREATE INDEX IF NOT EXISTS idx_diff_contents_storage_type ON diff_contents(storage_type);
CREATE INDEX IF NOT EXISTS idx_diff_contents_file_path ON diff_contents(file_path);
CREATE INDEX IF NOT EXISTS idx_diff_contents_change_type ON diff_contents(change_type);
CREATE INDEX IF NOT EXISTS idx_diff_contents_processing_status ON diff_contents(processing_status);
CREATE INDEX IF NOT EXISTS idx_diff_contents_created_at ON diff_contents(created_at);

CREATE INDEX IF NOT EXISTS idx_diff_queue_status ON diff_processing_queue(queue_status);
CREATE INDEX IF NOT EXISTS idx_diff_queue_priority ON diff_processing_queue(priority DESC);
CREATE INDEX IF NOT EXISTS idx_diff_queue_repository_id ON diff_processing_queue(repository_id);
CREATE INDEX IF NOT EXISTS idx_diff_queue_created_at ON diff_processing_queue(created_at);

CREATE INDEX IF NOT EXISTS idx_diff_stats_repository_id ON diff_statistics(repository_id);
CREATE INDEX IF NOT EXISTS idx_diff_stats_period ON diff_statistics(period_start, period_end);

-- Triggers for Updated At Columns
CREATE TRIGGER update_diff_contents_updated_at BEFORE UPDATE ON diff_contents
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_diff_queue_updated_at BEFORE UPDATE ON diff_processing_queue
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- Helper Functions
-- Function to get diff storage statistics for a repository
CREATE OR REPLACE FUNCTION get_repository_diff_stats(repo_id UUID, days_back INTEGER DEFAULT 30)
RETURNS TABLE (
  total_diffs BIGINT,
  total_size_bytes BIGINT,
  avg_size_bytes DECIMAL(10,2),
  storage_breakdown JSONB
) AS $$
BEGIN
  RETURN QUERY
  SELECT 
    COUNT(*)::BIGINT as total_diffs,
    COALESCE(SUM(dc.diff_size_bytes), 0)::BIGINT as total_size_bytes,
    COALESCE(AVG(dc.diff_size_bytes), 0)::DECIMAL(10,2) as avg_size_bytes,
    jsonb_build_object(
      'external', COUNT(*) FILTER (WHERE dc.storage_type = 'external')
    ) as storage_breakdown
  FROM diff_contents dc
  JOIN repository_commit_details rcd ON dc.commit_id = rcd.id
  WHERE rcd.repository_id = repo_id
    AND dc.created_at >= NOW() - INTERVAL '1 day' * days_back;
END;
$$ LANGUAGE plpgsql;

-- Function to clean up old diff processing queue entries
CREATE OR REPLACE FUNCTION cleanup_old_diff_queue_entries(days_back INTEGER DEFAULT 7)
RETURNS INTEGER AS $$
DECLARE
  deleted_count INTEGER;
BEGIN
  DELETE FROM diff_processing_queue 
  WHERE created_at < NOW() - INTERVAL '1 day' * days_back
    AND queue_status IN ('completed', 'failed');
  
  GET DIAGNOSTICS deleted_count = ROW_COUNT;
  RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;
