-- ============================================
-- TEMPLATE-SAAS: Sales Functions
-- Version: 1.0.0
-- Module: SAAS-018
-- ============================================

-- ============================================
-- Function: Convert Lead to Opportunity
-- ============================================
CREATE OR REPLACE FUNCTION sales.convert_lead_to_opportunity(
    p_lead_id UUID,
    p_opportunity_name VARCHAR(255) DEFAULT NULL,
    p_amount DECIMAL(15, 2) DEFAULT 0,
    p_expected_close_date DATE DEFAULT NULL
)
RETURNS UUID AS $$
DECLARE
    v_lead RECORD;
    v_opportunity_id UUID;
    v_tenant_id UUID;
BEGIN
    -- Get lead data
    SELECT * INTO v_lead
    FROM sales.leads
    WHERE id = p_lead_id
      AND deleted_at IS NULL
      AND status != 'converted';

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Lead not found or already converted';
    END IF;

    v_tenant_id := v_lead.tenant_id;

    -- Create opportunity
    INSERT INTO sales.opportunities (
        tenant_id,
        name,
        lead_id,
        stage,
        amount,
        currency,
        expected_close_date,
        assigned_to,
        contact_name,
        contact_email,
        contact_phone,
        company_name,
        notes,
        created_by
    ) VALUES (
        v_tenant_id,
        COALESCE(p_opportunity_name, v_lead.company || ' - ' || v_lead.first_name || ' ' || v_lead.last_name),
        p_lead_id,
        'prospecting',
        COALESCE(p_amount, 0),
        'USD',
        COALESCE(p_expected_close_date, CURRENT_DATE + INTERVAL '30 days'),
        v_lead.assigned_to,
        v_lead.first_name || ' ' || v_lead.last_name,
        v_lead.email,
        v_lead.phone,
        v_lead.company,
        v_lead.notes,
        v_lead.created_by
    )
    RETURNING id INTO v_opportunity_id;

    -- Update lead as converted
    UPDATE sales.leads
    SET status = 'converted',
        converted_at = NOW(),
        converted_to_opportunity_id = v_opportunity_id
    WHERE id = p_lead_id;

    RETURN v_opportunity_id;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION sales.convert_lead_to_opportunity IS 'Converts a lead to an opportunity, copying relevant data';

-- ============================================
-- Function: Update Opportunity Stage
-- ============================================
CREATE OR REPLACE FUNCTION sales.update_opportunity_stage(
    p_opportunity_id UUID,
    p_new_stage sales.opportunity_stage,
    p_notes TEXT DEFAULT NULL
)
RETURNS BOOLEAN AS $$
DECLARE
    v_opportunity RECORD;
BEGIN
    -- Get current opportunity
    SELECT * INTO v_opportunity
    FROM sales.opportunities
    WHERE id = p_opportunity_id
      AND deleted_at IS NULL;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Opportunity not found';
    END IF;

    -- Update stage
    UPDATE sales.opportunities
    SET stage = p_new_stage,
        notes = CASE
            WHEN p_notes IS NOT NULL THEN COALESCE(notes, '') || E'\n\n[Stage Change] ' || p_notes
            ELSE notes
        END,
        won_at = CASE WHEN p_new_stage = 'closed_won' THEN NOW() ELSE won_at END,
        lost_at = CASE WHEN p_new_stage = 'closed_lost' THEN NOW() ELSE lost_at END,
        actual_close_date = CASE
            WHEN p_new_stage IN ('closed_won', 'closed_lost') THEN CURRENT_DATE
            ELSE actual_close_date
        END
    WHERE id = p_opportunity_id;

    RETURN TRUE;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION sales.update_opportunity_stage IS 'Updates opportunity stage with automatic win/loss tracking';

-- ============================================
-- Function: Calculate Lead Score
-- ============================================
CREATE OR REPLACE FUNCTION sales.calculate_lead_score(
    p_lead_id UUID
)
RETURNS INT AS $$
DECLARE
    v_lead RECORD;
    v_score INT := 0;
    v_activity_count INT;
BEGIN
    -- Get lead data
    SELECT * INTO v_lead
    FROM sales.leads
    WHERE id = p_lead_id
      AND deleted_at IS NULL;

    IF NOT FOUND THEN
        RETURN 0;
    END IF;

    -- Base score for having email
    IF v_lead.email IS NOT NULL THEN
        v_score := v_score + 10;
    END IF;

    -- Score for phone
    IF v_lead.phone IS NOT NULL THEN
        v_score := v_score + 10;
    END IF;

    -- Score for company
    IF v_lead.company IS NOT NULL THEN
        v_score := v_score + 15;
    END IF;

    -- Score based on source
    CASE v_lead.source
        WHEN 'referral' THEN v_score := v_score + 20;
        WHEN 'website' THEN v_score := v_score + 15;
        WHEN 'event' THEN v_score := v_score + 10;
        ELSE v_score := v_score + 5;
    END CASE;

    -- Score based on status
    CASE v_lead.status
        WHEN 'qualified' THEN v_score := v_score + 25;
        WHEN 'contacted' THEN v_score := v_score + 15;
        WHEN 'new' THEN v_score := v_score + 5;
        ELSE NULL;
    END CASE;

    -- Score for activities
    SELECT COUNT(*) INTO v_activity_count
    FROM sales.activities
    WHERE lead_id = p_lead_id
      AND deleted_at IS NULL;

    v_score := v_score + LEAST(v_activity_count * 5, 20);

    -- Cap at 100
    RETURN LEAST(v_score, 100);
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION sales.calculate_lead_score IS 'Calculates a lead score based on completeness and engagement';

-- ============================================
-- Function: Get Pipeline Summary
-- ============================================
CREATE OR REPLACE FUNCTION sales.get_pipeline_summary(
    p_tenant_id UUID
)
RETURNS TABLE (
    stage sales.opportunity_stage,
    count BIGINT,
    total_amount DECIMAL(15, 2),
    avg_probability NUMERIC
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        o.stage,
        COUNT(*)::BIGINT,
        COALESCE(SUM(o.amount), 0)::DECIMAL(15, 2),
        COALESCE(AVG(o.probability), 0)::NUMERIC
    FROM sales.opportunities o
    WHERE o.tenant_id = p_tenant_id
      AND o.deleted_at IS NULL
    GROUP BY o.stage
    ORDER BY
        CASE o.stage
            WHEN 'prospecting' THEN 1
            WHEN 'qualification' THEN 2
            WHEN 'proposal' THEN 3
            WHEN 'negotiation' THEN 4
            WHEN 'closed_won' THEN 5
            WHEN 'closed_lost' THEN 6
        END;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION sales.get_pipeline_summary IS 'Returns summary of opportunities by stage for a tenant';

-- ============================================
-- Function: Initialize Default Pipeline Stages
-- ============================================
CREATE OR REPLACE FUNCTION sales.initialize_default_stages(
    p_tenant_id UUID
)
RETURNS VOID AS $$
BEGIN
    -- Insert default stages if none exist
    IF NOT EXISTS (SELECT 1 FROM sales.pipeline_stages WHERE tenant_id = p_tenant_id) THEN
        INSERT INTO sales.pipeline_stages (tenant_id, name, position, color, is_won, is_lost)
        VALUES
            (p_tenant_id, 'Prospecting', 1, '#94A3B8', FALSE, FALSE),
            (p_tenant_id, 'Qualification', 2, '#3B82F6', FALSE, FALSE),
            (p_tenant_id, 'Proposal', 3, '#8B5CF6', FALSE, FALSE),
            (p_tenant_id, 'Negotiation', 4, '#F59E0B', FALSE, FALSE),
            (p_tenant_id, 'Closed Won', 5, '#10B981', TRUE, FALSE),
            (p_tenant_id, 'Closed Lost', 6, '#EF4444', FALSE, TRUE);
    END IF;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION sales.initialize_default_stages IS 'Creates default pipeline stages for a new tenant';
