-- Create letter_summary table for daily aggregated statistics
CREATE TABLE IF NOT EXISTS letter_summary (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    summary_date DATE NOT NULL,
    letter_type VARCHAR(20) NOT NULL, -- 'incoming' or 'outgoing'
    total_count INTEGER DEFAULT 0,
    pending_count INTEGER DEFAULT 0,
    approved_count INTEGER DEFAULT 0,
    rejected_count INTEGER DEFAULT 0,
    archived_count INTEGER DEFAULT 0,
    sent_count INTEGER DEFAULT 0,
    avg_processing_hours DECIMAL(10,2),
    min_processing_hours DECIMAL(10,2),
    max_processing_hours DECIMAL(10,2),
    median_processing_hours DECIMAL(10,2),
    p95_processing_hours DECIMAL(10,2),
    p99_processing_hours DECIMAL(10,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(summary_date, letter_type)
);

-- Create department_letter_summary table
CREATE TABLE IF NOT EXISTS department_letter_summary (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    department_id UUID NOT NULL REFERENCES departments(id),
    summary_date DATE NOT NULL,
    incoming_count INTEGER DEFAULT 0,
    outgoing_count INTEGER DEFAULT 0,
    pending_incoming INTEGER DEFAULT 0,
    pending_outgoing INTEGER DEFAULT 0,
    approved_outgoing INTEGER DEFAULT 0,
    rejected_outgoing INTEGER DEFAULT 0,
    avg_response_hours DECIMAL(10,2),
    completion_rate DECIMAL(5,2),
    total_recipients INTEGER DEFAULT 0,
    unique_senders INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(department_id, summary_date)
);

-- Create institution_letter_summary table
CREATE TABLE IF NOT EXISTS institution_letter_summary (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    institution_id UUID NOT NULL REFERENCES institutions(id),
    summary_date DATE NOT NULL,
    incoming_sent INTEGER DEFAULT 0,
    outgoing_received INTEGER DEFAULT 0,
    total_correspondence INTEGER DEFAULT 0,
    avg_turnaround_hours DECIMAL(10,2),
    last_activity_at TIMESTAMP,
    priority_high_count INTEGER DEFAULT 0,
    priority_medium_count INTEGER DEFAULT 0,
    priority_low_count INTEGER DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(institution_id, summary_date)
);

-- Create approval_sla_summary table
CREATE TABLE IF NOT EXISTS approval_sla_summary (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    summary_date DATE NOT NULL,
    department_id UUID REFERENCES departments(id),
    total_approvals INTEGER DEFAULT 0,
    approved_count INTEGER DEFAULT 0,
    rejected_count INTEGER DEFAULT 0,
    pending_count INTEGER DEFAULT 0,
    avg_approval_hours DECIMAL(10,2),
    min_approval_hours DECIMAL(10,2),
    max_approval_hours DECIMAL(10,2),
    median_approval_hours DECIMAL(10,2),
    within_sla_count INTEGER DEFAULT 0,
    exceeded_sla_count INTEGER DEFAULT 0,
    sla_compliance_rate DECIMAL(5,2),
    avg_approval_steps DECIMAL(5,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(summary_date, department_id)
);

-- Create indexes for better query performance
CREATE INDEX idx_letter_summary_date ON letter_summary(summary_date DESC);
CREATE INDEX idx_letter_summary_type_date ON letter_summary(letter_type, summary_date DESC);

CREATE INDEX idx_dept_letter_summary_dept_date ON department_letter_summary(department_id, summary_date DESC);
CREATE INDEX idx_dept_letter_summary_date ON department_letter_summary(summary_date DESC);

CREATE INDEX idx_inst_letter_summary_inst_date ON institution_letter_summary(institution_id, summary_date DESC);
CREATE INDEX idx_inst_letter_summary_date ON institution_letter_summary(summary_date DESC);

CREATE INDEX idx_approval_sla_summary_date ON approval_sla_summary(summary_date DESC);
CREATE INDEX idx_approval_sla_summary_dept_date ON approval_sla_summary(department_id, summary_date DESC);

-- Create function to update letter_summary
CREATE OR REPLACE FUNCTION update_letter_summary()
RETURNS TRIGGER AS $$
DECLARE
    v_date DATE;
    v_type VARCHAR(20);
BEGIN
    -- Determine date and type
    IF TG_TABLE_NAME = 'letters_incoming' THEN
        v_type := 'incoming';
        v_date := DATE(COALESCE(NEW.created_at, OLD.created_at));
    ELSE
        v_type := 'outgoing';
        v_date := DATE(COALESCE(NEW.created_at, OLD.created_at));
    END IF;

    -- Update or insert summary
    INSERT INTO letter_summary (
        summary_date,
        letter_type,
        total_count,
        pending_count,
        approved_count,
        rejected_count,
        archived_count,
        sent_count
    )
    SELECT 
        v_date,
        v_type,
        COUNT(*) as total_count,
        COUNT(*) FILTER (WHERE status = 'pending' OR status = 'pending_approval') as pending_count,
        COUNT(*) FILTER (WHERE status = 'approved') as approved_count,
        COUNT(*) FILTER (WHERE status = 'rejected') as rejected_count,
        COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
        COUNT(*) FILTER (WHERE status = 'sent') as sent_count
    FROM (
        SELECT status, created_at FROM letters_incoming WHERE DATE(created_at) = v_date AND v_type = 'incoming'
        UNION ALL
        SELECT status, created_at FROM letters_outgoing WHERE DATE(created_at) = v_date AND v_type = 'outgoing'
    ) t
    ON CONFLICT (summary_date, letter_type) 
    DO UPDATE SET
        total_count = EXCLUDED.total_count,
        pending_count = EXCLUDED.pending_count,
        approved_count = EXCLUDED.approved_count,
        rejected_count = EXCLUDED.rejected_count,
        archived_count = EXCLUDED.archived_count,
        sent_count = EXCLUDED.sent_count,
        updated_at = CURRENT_TIMESTAMP;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Create triggers for automatic updates
CREATE TRIGGER update_letter_summary_on_incoming
    AFTER INSERT OR UPDATE OR DELETE ON letters_incoming
    FOR EACH ROW
    EXECUTE FUNCTION update_letter_summary();

CREATE TRIGGER update_letter_summary_on_outgoing
    AFTER INSERT OR UPDATE OR DELETE ON letters_outgoing
    FOR EACH ROW
    EXECUTE FUNCTION update_letter_summary();

-- Function to populate historical data
CREATE OR REPLACE FUNCTION populate_letter_summary_history()
RETURNS void AS $$
BEGIN
    -- Populate letter_summary with historical data
    INSERT INTO letter_summary (
        summary_date,
        letter_type,
        total_count,
        pending_count,
        approved_count,
        rejected_count,
        archived_count,
        sent_count,
        avg_processing_hours
    )
    SELECT 
        DATE(created_at) as summary_date,
        'incoming' as letter_type,
        COUNT(*) as total_count,
        COUNT(*) FILTER (WHERE status = 'pending') as pending_count,
        COUNT(*) FILTER (WHERE status = 'approved') as approved_count,
        COUNT(*) FILTER (WHERE status = 'rejected') as rejected_count,
        COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
        0 as sent_count,
        AVG(EXTRACT(EPOCH FROM (updated_at - created_at))/3600) as avg_processing_hours
    FROM letters_incoming
    WHERE deleted_at IS NULL
    GROUP BY DATE(created_at)
    UNION ALL
    SELECT 
        DATE(created_at) as summary_date,
        'outgoing' as letter_type,
        COUNT(*) as total_count,
        COUNT(*) FILTER (WHERE status = 'pending_approval') as pending_count,
        COUNT(*) FILTER (WHERE status = 'approved') as approved_count,
        COUNT(*) FILTER (WHERE status = 'rejected') as rejected_count,
        COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
        COUNT(*) FILTER (WHERE status = 'sent') as sent_count,
        AVG(EXTRACT(EPOCH FROM (updated_at - created_at))/3600) as avg_processing_hours
    FROM letters_outgoing
    WHERE deleted_at IS NULL
    GROUP BY DATE(created_at)
    ON CONFLICT (summary_date, letter_type) DO NOTHING;

    -- Populate department_letter_summary
    INSERT INTO department_letter_summary (
        department_id,
        summary_date,
        incoming_count,
        outgoing_count,
        pending_incoming,
        pending_outgoing,
        approved_outgoing,
        rejected_outgoing,
        avg_response_hours,
        completion_rate
    )
    SELECT 
        d.id as department_id,
        dates.summary_date,
        COALESCE(inc.count, 0) as incoming_count,
        COALESCE(outg.count, 0) as outgoing_count,
        COALESCE(inc.pending, 0) as pending_incoming,
        COALESCE(outg.pending, 0) as pending_outgoing,
        COALESCE(outg.approved, 0) as approved_outgoing,
        COALESCE(outg.rejected, 0) as rejected_outgoing,
        COALESCE(outg.avg_hours, 0) as avg_response_hours,
        CASE 
            WHEN COALESCE(outg.count, 0) > 0 
            THEN (COALESCE(outg.completed, 0)::DECIMAL / outg.count::DECIMAL) * 100
            ELSE 0 
        END as completion_rate
    FROM departments d
    CROSS JOIN (
        SELECT DISTINCT DATE(created_at) as summary_date 
        FROM letters_incoming 
        UNION 
        SELECT DISTINCT DATE(created_at) 
        FROM letters_outgoing
    ) dates
    LEFT JOIN (
        SELECT 
            lir.recipient_department_id as dept_id,
            DATE(li.created_at) as date,
            COUNT(DISTINCT li.id) as count,
            COUNT(DISTINCT li.id) FILTER (WHERE li.status = 'pending') as pending
        FROM letters_incoming li
        JOIN letter_incoming_recipients lir ON lir.letter_id = li.id
        WHERE li.deleted_at IS NULL
        GROUP BY lir.recipient_department_id, DATE(li.created_at)
    ) inc ON inc.dept_id = d.id AND inc.date = dates.summary_date
    LEFT JOIN (
        SELECT 
            lor.department_id as dept_id,
            DATE(lo.created_at) as date,
            COUNT(DISTINCT lo.id) as count,
            COUNT(DISTINCT lo.id) FILTER (WHERE lo.status = 'pending_approval') as pending,
            COUNT(DISTINCT lo.id) FILTER (WHERE lo.status = 'approved') as approved,
            COUNT(DISTINCT lo.id) FILTER (WHERE lo.status = 'rejected') as rejected,
            COUNT(DISTINCT lo.id) FILTER (WHERE lo.status IN ('sent', 'archived')) as completed,
            AVG(EXTRACT(EPOCH FROM (lo.updated_at - lo.created_at))/3600) as avg_hours
        FROM letters_outgoing lo
        JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id
        WHERE lo.deleted_at IS NULL
        GROUP BY lor.department_id, DATE(lo.created_at)
    ) outg ON outg.dept_id = d.id AND outg.date = dates.summary_date
    WHERE inc.count > 0 OR outg.count > 0
    ON CONFLICT (department_id, summary_date) DO NOTHING;

    -- Populate institution_letter_summary
    INSERT INTO institution_letter_summary (
        institution_id,
        summary_date,
        incoming_sent,
        outgoing_received,
        total_correspondence,
        avg_turnaround_hours,
        last_activity_at,
        priority_high_count,
        priority_medium_count,
        priority_low_count
    )
    SELECT 
        i.id as institution_id,
        dates.summary_date,
        COALESCE(inc.count, 0) as incoming_sent,
        COALESCE(outg.count, 0) as outgoing_received,
        COALESCE(inc.count, 0) + COALESCE(outg.count, 0) as total_correspondence,
        COALESCE((inc.avg_hours + outg.avg_hours) / 2, 0) as avg_turnaround_hours,
        GREATEST(inc.last_activity, outg.last_activity) as last_activity_at,
        COALESCE(inc.high_priority, 0) + COALESCE(outg.high_priority, 0) as priority_high_count,
        COALESCE(inc.medium_priority, 0) + COALESCE(outg.medium_priority, 0) as priority_medium_count,
        COALESCE(inc.low_priority, 0) + COALESCE(outg.low_priority, 0) as priority_low_count
    FROM institutions i
    CROSS JOIN (
        SELECT DISTINCT DATE(created_at) as summary_date 
        FROM letters_incoming 
        UNION 
        SELECT DISTINCT DATE(created_at) 
        FROM letters_outgoing
    ) dates
    LEFT JOIN (
        SELECT 
            sender_institution_id as inst_id,
            DATE(created_at) as date,
            COUNT(*) as count,
            AVG(EXTRACT(EPOCH FROM (updated_at - created_at))/3600) as avg_hours,
            MAX(created_at) as last_activity,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 1)) as high_priority,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 2)) as medium_priority,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 3)) as low_priority
        FROM letters_incoming
        WHERE deleted_at IS NULL AND sender_institution_id IS NOT NULL
        GROUP BY sender_institution_id, DATE(created_at)
    ) inc ON inc.inst_id = i.id AND inc.date = dates.summary_date
    LEFT JOIN (
        SELECT 
            receiver_institution_id as inst_id,
            DATE(created_at) as date,
            COUNT(*) as count,
            AVG(EXTRACT(EPOCH FROM (updated_at - created_at))/3600) as avg_hours,
            MAX(created_at) as last_activity,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 1)) as high_priority,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 2)) as medium_priority,
            COUNT(*) FILTER (WHERE priority_id IN (SELECT id FROM priorities WHERE level = 3)) as low_priority
        FROM letters_outgoing
        WHERE deleted_at IS NULL AND receiver_institution_id IS NOT NULL
        GROUP BY receiver_institution_id, DATE(created_at)
    ) outg ON outg.inst_id = i.id AND outg.date = dates.summary_date
    WHERE inc.count > 0 OR outg.count > 0
    ON CONFLICT (institution_id, summary_date) DO NOTHING;

    -- Populate approval_sla_summary
    INSERT INTO approval_sla_summary (
        summary_date,
        department_id,
        total_approvals,
        approved_count,
        rejected_count,
        pending_count,
        avg_approval_hours,
        min_approval_hours,
        max_approval_hours,
        median_approval_hours,
        within_sla_count,
        exceeded_sla_count,
        sla_compliance_rate,
        avg_approval_steps
    )
    SELECT 
        DATE(loa.created_at) as summary_date,
        d.id as department_id,
        COUNT(loa.id) as total_approvals,
        COUNT(loa.id) FILTER (WHERE loa.status = 'approved') as approved_count,
        COUNT(loa.id) FILTER (WHERE loa.status = 'rejected') as rejected_count,
        COUNT(loa.id) FILTER (WHERE loa.status = 'pending') as pending_count,
        AVG(EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600) FILTER (WHERE loa.acted_at IS NOT NULL) as avg_approval_hours,
        MIN(EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600) FILTER (WHERE loa.acted_at IS NOT NULL) as min_approval_hours,
        MAX(EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600) FILTER (WHERE loa.acted_at IS NOT NULL) as max_approval_hours,
        PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600) FILTER (WHERE loa.acted_at IS NOT NULL) as median_approval_hours,
        COUNT(loa.id) FILTER (WHERE EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600 <= 24 AND loa.acted_at IS NOT NULL) as within_sla_count,
        COUNT(loa.id) FILTER (WHERE EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600 > 24 AND loa.acted_at IS NOT NULL) as exceeded_sla_count,
        CASE 
            WHEN COUNT(loa.id) FILTER (WHERE loa.acted_at IS NOT NULL) > 0
            THEN (COUNT(loa.id) FILTER (WHERE EXTRACT(EPOCH FROM (loa.acted_at - loa.created_at))/3600 <= 24 AND loa.acted_at IS NOT NULL)::DECIMAL / 
                  COUNT(loa.id) FILTER (WHERE loa.acted_at IS NOT NULL)::DECIMAL) * 100
            ELSE 0
        END as sla_compliance_rate,
        AVG(step_counts.step_count) as avg_approval_steps
    FROM letter_outgoing_approvals loa
    JOIN letters_outgoing lo ON lo.id = loa.letter_id
    JOIN letter_outgoing_recipients lor ON lor.letter_id = lo.id
    JOIN departments d ON d.id = lor.department_id
    LEFT JOIN (
        SELECT letter_id, COUNT(*) as step_count
        FROM letter_outgoing_approvals
        GROUP BY letter_id
    ) step_counts ON step_counts.letter_id = loa.letter_id
    WHERE lo.deleted_at IS NULL
    GROUP BY DATE(loa.created_at), d.id
    ON CONFLICT (summary_date, department_id) DO NOTHING;

END;
$$ LANGUAGE plpgsql;

-- Execute the function to populate historical data
SELECT populate_letter_summary_history();