<?php
/**
 * Repertory Engine
 * Core repertorization algorithms for Kent's Repertory
 */

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../config/constants.php';
require_once __DIR__ . '/functions.php';

// ============================================
// CORE REPERTORIZATION
// ============================================

/**
 * Main repertorization function
 * @param array $selectedRubrics Array of rubric IDs with optional weights
 * @param array $options Additional options (constitutional_weight, etc.)
 * @return array Sorted remedies with scores and details
 */
function repertorize($selectedRubrics, $options = []) {
    if (empty($selectedRubrics)) {
        return [];
    }
    
    $pdo = getDB();
    $scores = [];
    $rubricDetails = [];
    
    // Build rubric IDs array
    $rubricIds = is_array($selectedRubrics) ? array_keys($selectedRubrics) : $selectedRubrics;
    
    if (empty($rubricIds)) {
        return [];
    }
    
    // Get all remedies for selected rubrics
    $placeholders = implode(',', array_fill(0, count($rubricIds), '?'));
    $sql = "SELECT rr.rubric_id, rr.remedy_id, rr.grade, 
                   r.rubric_name, r.full_path, r.level,
                   rm.name as remedy_name, rm.abbreviation
            FROM rubric_remedy rr
            JOIN rubrics r ON rr.rubric_id = r.id
            JOIN remedies rm ON rr.remedy_id = rm.id
            WHERE rr.rubric_id IN ($placeholders)";
    
    $stmt = $pdo->prepare($sql);
    $stmt->execute($rubricIds);
    $results = $stmt->fetchAll();
    
    // Score calculation
    foreach ($results as $row) {
        $remedyId = $row['remedy_id'];
        $remedyName = $row['remedy_name'];
        $grade = $row['grade'];
        $weight = GRADE_WEIGHTS[$grade];
        
        // Apply rubric weight if custom
        $rubricWeight = 1;
        if (is_array($selectedRubrics) && isset($selectedRubrics[$row['rubric_id']])) {
            $rubricWeight = $selectedRubrics[$row['rubric_id']]['weight'] ?? 1;
        }
        
        $score = $weight * $rubricWeight;
        
        if (!isset($scores[$remedyId])) {
            $scores[$remedyId] = [
                'id' => $remedyId,
                'name' => $remedyName,
                'abbreviation' => $row['abbreviation'],
                'score' => 0,
                'grades' => [],
                'rubrics' => [],
                'rubric_ids' => [],
                'grade_summary' => [1 => 0, 2 => 0, 3 => 0, 4 => 0]
            ];
        }
        
        $scores[$remedyId]['score'] += $score;
        $scores[$remedyId]['grades'][] = $grade;
        $scores[$remedyId]['grade_summary'][$grade]++;
        $scores[$remedyId]['rubrics'][] = $row['full_path'];
        $scores[$remedyId]['rubric_ids'][] = $row['rubric_id'];
    }
    
    // Apply constitutional weighting if specified
    if (!empty($options['constitutional_rubrics'])) {
        $scores = applyConstitutionalWeight($scores, $options['constitutional_rubrics']);
    }
    
    // Apply rubric rarity weighting (rare rubrics get higher weight)
    if (!empty($options['rarity_weight'])) {
        $scores = applyRarityWeight($scores);
    }
    
    // Sort by score descending
    uasort($scores, function($a, $b) {
        if ($b['score'] == $a['score']) {
            // If scores equal, higher grade 4 count wins
            return $b['grade_summary'][4] <=> $a['grade_summary'][4];
        }
        return $b['score'] <=> $a['score'];
    });
    
    return $scores;
}

/**
 * Quick repertorization for AJAX (lightweight)
 * @param array $rubricIds
 * @param int $limit
 * @return array
 */
function quickRepertorize($rubricIds, $limit = 20) {
    if (empty($rubricIds)) {
        return [];
    }
    
    $pdo = getDB();
    $placeholders = implode(',', array_fill(0, count($rubricIds), '?'));
    
    $sql = "SELECT rm.id, rm.name, rm.abbreviation, 
                   SUM(" . GRADE_WEIGHTS[4] . " * (rr.grade = 4) + 
                       " . GRADE_WEIGHTS[3] . " * (rr.grade = 3) + 
                       " . GRADE_WEIGHTS[2] . " * (rr.grade = 2) + 
                       " . GRADE_WEIGHTS[1] . " * (rr.grade = 1)) as score
            FROM rubric_remedy rr
            JOIN remedies rm ON rr.remedy_id = rm.id
            WHERE rr.rubric_id IN ($placeholders)
            GROUP BY rm.id
            ORDER BY score DESC
            LIMIT $limit";
    
    $stmt = $pdo->prepare($sql);
    $stmt->execute($rubricIds);
    return $stmt->fetchAll();
}

// ============================================
// ADVANCED WEIGHTING FUNCTIONS
// ============================================

/**
 * Apply constitutional weighting to scores
 * @param array $scores
 * @param array $constitutionalRubrics
 * @return array
 */
function applyConstitutionalWeight($scores, $constitutionalRubrics) {
    $constitutionalWeight = 1.5; // 50% boost for constitutional matches
    
    foreach ($scores as &$remedy) {
        $matchCount = 0;
        foreach ($constitutionalRubrics as $conRubricId) {
            if (in_array($conRubricId, $remedy['rubric_ids'])) {
                $matchCount++;
            }
        }
        
        if ($matchCount > 0) {
            $remedy['score'] = $remedy['score'] * (1 + ($matchCount * 0.1));
            $remedy['constitutional_match'] = $matchCount;
        }
    }
    
    return $scores;
}

/**
 * Apply rarity weighting (rubrics with few remedies get higher weight)
 * @param array $scores
 * @return array
 */
function applyRarityWeight($scores) {
    $pdo = getDB();
    
    // Cache rubric rarity
    static $rubricRarity = null;
    if ($rubricRarity === null) {
        $stmt = $pdo->query("SELECT rubric_id, COUNT(*) as remedy_count 
                            FROM rubric_remedy 
                            GROUP BY rubric_id");
        $rarity = $stmt->fetchAll();
        $rubricRarity = [];
        foreach ($rarity as $r) {
            $rubricRarity[$r['rubric_id']] = $r['remedy_count'];
        }
    }
    
    foreach ($scores as &$remedy) {
        $rarityBonus = 0;
        foreach ($remedy['rubric_ids'] as $rubricId) {
            $remedyCount = $rubricRarity[$rubricId] ?? 10;
            if ($remedyCount <= 3) {
                $rarityBonus += 5; // Very rare rubric
            } elseif ($remedyCount <= 10) {
                $rarityBonus += 2; // Rare rubric
            }
        }
        $remedy['score'] += $rarityBonus;
    }
    
    return $scores;
}

// ============================================
// CASE-BASED REPERTORIZATION
// ============================================

/**
 * Repertorize from case data
 * @param array $caseData
 * @return array
 */
function repertorizeFromCase($caseData) {
    $selectedRubrics = [];
    
    // Extract rubrics from case
    if (!empty($caseData['selected_rubrics'])) {
        $selectedRubrics = json_decode($caseData['selected_rubrics'], true);
    }
    
    // Add rubrics from symptoms if AI extraction is used
    if (!empty($caseData['ai_extracted_rubrics'])) {
        foreach ($caseData['ai_extracted_rubrics'] as $rubric) {
            if (!isset($selectedRubrics[$rubric['id']])) {
                $selectedRubrics[$rubric['id']] = ['weight' => $rubric['weight'] ?? 1];
            }
        }
    }
    
    // Add mental/emotional rubrics with higher weight
    if (!empty($caseData['mental_emotional'])) {
        $mentalRubrics = extractMentalRubrics($caseData['mental_emotional']);
        foreach ($mentalRubrics as $rubricId) {
            if (!isset($selectedRubrics[$rubricId])) {
                $selectedRubrics[$rubricId] = ['weight' => 1.5]; // 50% weight increase
            } else {
                $selectedRubrics[$rubricId]['weight'] *= 1.5;
            }
        }
    }
    
    // Add modalities
    if (!empty($caseData['modalities'])) {
        $modalityRubrics = extractModalityRubrics($caseData['modalities']);
        foreach ($modalityRubrics as $rubricId) {
            if (!isset($selectedRubrics[$rubricId])) {
                $selectedRubrics[$rubricId] = ['weight' => 1.2];
            }
        }
    }
    
    return repertorize($selectedRubrics);
}

// ============================================
// RUBRIC EXTRACTION HELPERS
// ============================================

/**
 * Extract mental/emotional rubrics from text
 * @param string $text
 * @return array
 */
function extractMentalRubrics($text) {
    $pdo = getDB();
    $rubricIds = [];
    
    // Common mental rubric keywords
    $keywords = [
        'anxiety' => 'MIND - ANXIETY',
        'fear' => 'MIND - FEAR',
        'anger' => 'MIND - ANGER',
        'irritability' => 'MIND - IRRITABILITY',
        'depression' => 'MIND - SADNESS',
        'weeping' => 'MIND - WEEPING',
        'forgetful' => 'MIND - FORGETFULNESS',
        'confusion' => 'MIND - CONFUSION'
    ];
    
    $textLower = strtolower($text);
    
    foreach ($keywords as $keyword => $path) {
        if (strpos($textLower, $keyword) !== false) {
            $stmt = $pdo->prepare("SELECT id FROM rubrics WHERE full_path LIKE ?");
            $stmt->execute(["$path%"]);
            while ($row = $stmt->fetch()) {
                $rubricIds[] = $row['id'];
            }
        }
    }
    
    return array_unique($rubricIds);
}

/**
 * Extract modality rubrics from text
 * @param string $text
 * @return array
 */
function extractModalityRubrics($text) {
    $pdo = getDB();
    $rubricIds = [];
    
    $modalities = [
        'worse' => ['night', 'cold', 'warm', 'motion', 'rest', 'eating', 'empty stomach'],
        'better' => ['warmth', 'cold', 'open air', 'lying', 'sitting', 'eating', 'pressure']
    ];
    
    $textLower = strtolower($text);
    
    foreach ($modalities['worse'] as $modality) {
        if (strpos($textLower, $modality) !== false) {
            $stmt = $pdo->prepare("SELECT id FROM rubrics WHERE full_path LIKE ?");
            $stmt->execute(["%WORSE - " . strtoupper($modality) . "%"]);
            while ($row = $stmt->fetch()) {
                $rubricIds[] = $row['id'];
            }
        }
    }
    
    foreach ($modalities['better'] as $modality) {
        if (strpos($textLower, $modality) !== false) {
            $stmt = $pdo->prepare("SELECT id FROM rubrics WHERE full_path LIKE ?");
            $stmt->execute(["%BETTER - " . strtoupper($modality) . "%"]);
            while ($row = $stmt->fetch()) {
                $rubricIds[] = $row['id'];
            }
        }
    }
    
    return array_unique($rubricIds);
}

// ============================================
// REMEDY COMPARISON
// ============================================

/**
 * Compare two remedies
 * @param int $remedyId1
 * @param int $remedyId2
 * @return array
 */
function compareRemedies($remedyId1, $remedyId2) {
    $pdo = getDB();
    
    // Get rubrics for both remedies
    $stmt = $pdo->prepare("SELECT r.full_path, rr.grade 
                          FROM rubric_remedy rr
                          JOIN rubrics r ON rr.rubric_id = r.id
                          WHERE rr.remedy_id = ?");
    
    $stmt->execute([$remedyId1]);
    $rubrics1 = $stmt->fetchAll();
    
    $stmt->execute([$remedyId2]);
    $rubrics2 = $stmt->fetchAll();
    
    $rubrics1Paths = array_column($rubrics1, 'full_path');
    $rubrics2Paths = array_column($rubrics2, 'full_path');
    
    return [
        'common' => array_intersect($rubrics1Paths, $rubrics2Paths),
        'only_in_first' => array_diff($rubrics1Paths, $rubrics2Paths),
        'only_in_second' => array_diff($rubrics2Paths, $rubrics1Paths),
        'total_rubrics_1' => count($rubrics1),
        'total_rubrics_2' => count($rubrics2)
    ];
}

/**
 * Get remedy differentials
 * @param int $remedyId
 * @param array $otherRemedyIds
 * @return array
 */
function getRemedyDifferentials($remedyId, $otherRemedyIds) {
    $pdo = getDB();
    
    $result = [];
    
    // Get key rubrics for main remedy (grade 3-4)
    $stmt = $pdo->prepare("SELECT r.full_path, rr.grade 
                          FROM rubric_remedy rr
                          JOIN rubrics r ON rr.rubric_id = r.id
                          WHERE rr.remedy_id = ? AND rr.grade >= 3");
    $stmt->execute([$remedyId]);
    $keyRubrics = $stmt->fetchAll();
    
    foreach ($keyRubrics as $rubric) {
        $result[$rubric['full_path']] = [
            'grade' => $rubric['grade'],
            'present_in_others' => []
        ];
        
        foreach ($otherRemedyIds as $otherId) {
            $stmt = $pdo->prepare("SELECT grade FROM rubric_remedy 
                                  WHERE remedy_id = ? AND rubric_id = 
                                  (SELECT id FROM rubrics WHERE full_path = ?)");
            $stmt->execute([$otherId, $rubric['full_path']]);
            $other = $stmt->fetch();
            
            if ($other) {
                $result[$rubric['full_path']]['present_in_others'][] = [
                    'remedy_id' => $otherId,
                    'grade' => $other['grade']
                ];
            }
        }
    }
    
    return $result;
}

// ============================================
// REPERTORIZATION HISTORY
// ============================================

/**
 * Save repertorization result
 * @param int $caseId
 * @param array $result
 * @return bool
 */
function saveRepertorizationResult($caseId, $result) {
    $pdo = getDB();
    
    $stmt = $pdo->prepare("UPDATE cases SET repertorization_result = ? WHERE id = ?");
    return $stmt->execute([json_encode($result), $caseId]);
}

/**
 * Get repertorization result for case
 * @param int $caseId
 * @return array|null
 */
function getRepertorizationResult($caseId) {
    $pdo = getDB();
    
    $stmt = $pdo->prepare("SELECT repertorization_result FROM cases WHERE id = ?");
    $stmt->execute([$caseId]);
    $result = $stmt->fetch();
    
    if ($result && $result['repertorization_result']) {
        return json_decode($result['repertorization_result'], true);
    }
    
    return null;
}

// ============================================
// STATISTICS & ANALYSIS
// ============================================

/**
 * Get most prescribed remedies
 * @param int $limit
 * @return array
 */
function getMostPrescribedRemedies($limit = 10) {
    $pdo = getDB();
    
    $sql = "SELECT r.id, r.name, COUNT(c.id) as prescription_count
            FROM remedies r
            LEFT JOIN cases c ON c.prescribed_remedy_id = r.id
            GROUP BY r.id
            ORDER BY prescription_count DESC
            LIMIT ?";
    
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$limit]);
    return $stmt->fetchAll();
}

/**
 * Get remedy usage statistics
 * @param int $remedyId
 * @return array
 */
function getRemedyStatistics($remedyId) {
    $pdo = getDB();
    
    $stats = [];
    
    // Total prescriptions
    $stmt = $pdo->prepare("SELECT COUNT(*) as count FROM cases WHERE prescribed_remedy_id = ?");
    $stmt->execute([$remedyId]);
    $stats['prescriptions'] = $stmt->fetch()['count'];
    
    // Success rate (based on follow-ups with improvement)
    $stmt = $pdo->prepare("SELECT COUNT(*) as improved 
                          FROM follow_ups f
                          JOIN cases c ON f.case_id = c.id
                          WHERE c.prescribed_remedy_id = ? 
                          AND f.progress LIKE '%improved%'");
    $stmt->execute([$remedyId]);
    $stats['improved'] = $stmt->fetch()['improved'];
    
    // Rubric count
    $stmt = $pdo->prepare("SELECT COUNT(*) as count FROM rubric_remedy WHERE remedy_id = ?");
    $stmt->execute([$remedyId]);
    $stats['rubrics'] = $stmt->fetch()['count'];
    
    // Grade distribution
    $stmt = $pdo->prepare("SELECT grade, COUNT(*) as count 
                          FROM rubric_remedy 
                          WHERE remedy_id = ? 
                          GROUP BY grade");
    $stmt->execute([$remedyId]);
    $stats['grades'] = $stmt->fetchAll();
    
    return $stats;
}