<?php

/**
 * validateMatches
 * @param unknown $matches
 */
function validateMatches($matches_arr, $wl_mysql, $searched_na_arr, $rule_arr){
    $final_matches = [];
    $metadata_matches = [];
    
    /**
     * MAIN - iterate over all rules and the rule array of matches
     */
    foreach($matches_arr as $rule=>$matches){
        
        //gets rules manadtory & optional fields
        $rule_fields_arr = getRuleFields($rule_arr, $rule);
        
        $keys_arr = $rule_arr[$rule]["keys"];
        $special_validation = false;
        
        $matches_ids = []; // for each mandatory_arr - to avoid duplicates
        foreach($keys_arr as $key_str){
            $mandatory_values_cond = true; //boolean to make sure we have ALL mandatory fields
            $mand_keys = explode('&', $key_str);
            foreach($mand_keys as &$k){
                $k = checkMappedCols($rule_arr[$rule]["mapped_cols"] ?? null, $k); //convert name of columns in needed (as in kunya)
            }
            
            $fields_arr = array_unique(array_merge($rule_fields_arr["optional"], $mand_keys));
            $fields_str = !empty($fields_arr) ? implode(',', $fields_arr): "";
            
            $mandatory_str = implode(',', $mand_keys);
            
            /**
             * iterate over each match
             */
            foreach($matches as $caption=>$ids_arr){
                foreach($ids_arr as $id_arr){
                    $person_refs = key($ids_arr);
                  
                    $person_refs_sql = implode("','", explode(',', $person_refs)); //take first id for refrence - will apply on all the rest of ids since its the same caption and data
                 
                    $person_refs_sql = "'".$person_refs_sql."'";
                 
                    $na_indexes = implode(',', array_unique(array_values($ids_arr))); //take first id for refrence - will apply on all the rest of ids since its the same caption and data 
                    $valid_count = 0;
                 
                    $temp_arr = [];
                    $valid_match= false;
                    /**
                     * check each match agsaints the name-alternative of the person
                     */
                    foreach($searched_na_arr as $searched_na){
                        $searched_na = array_filter($searched_na);
                        //if name alternative have Not even one mandatory field - skip
                        if(!checkAllMandatoryFields($searched_na, $mand_keys)){
                            continue;
                        }
                        $sql = "SELECT caption,$fields_str FROM full_analysis WHERE  person_ref  IN($person_refs_sql) AND na_index IN($na_indexes) GROUP BY $mandatory_str";
                        $res = sqlQuery($wl_mysql, $sql);
                        
                        $check_valid = -1;
                        
                        while ($row = $res->fetch_object()){
                            $match_vals = array_filter(json_decode(json_encode($row), TRUE));
                            
                            //if the match has not even one mandatory field - skip
                            if(!checkAllMandatoryFields($match_vals, $mand_keys)){
                                continue;
                            }
                            
                            $na_keys = array_filter(array_intersect($fields_arr, array_keys($searched_na)));
                            $match_keys = array_filter(array_intersect($fields_arr, array_keys($match_vals)));
                            
                            $mutual_keys = array_unique(array_merge($na_keys,$match_keys));
                            
                            if(!empty($rule_arr[$rule]["special_validation"])){
                                $valid_count = validKeysByRule($rule, $match_vals, $searched_na, $mutual_keys);
                            }
    
                            else{
                                $valid_count = validateValues($mutual_keys, $match_vals, $searched_na, $mand_keys, $rule_arr[$rule]["mapped_cols"] ?? null);                         
                            }
                            
                            $total_count = count($mutual_keys);
                            
                            //if its relation matching - and its the same values for the searched NA and match
                            if(!empty($rule_arr[$rule]["relation"]) || $rule == "kunya"){
                                if(sameGN($match_vals, $searched_na)){
                                    continue;
                                }
                            }
                           
                            //check if the 2 values arrays valid - if so - can skip and match the person - since one NA already enough for approve this match
                            if($valid_count > 0){
                                $match = ["Name"=>$caption,"ID"=>$person_refs, "na_indexes"=>$na_indexes];                
                             
                                //if its partial same person - no confidence              
                                if(!in_array($rule,["possible_same_person_gn","possible_same_person_fn"])){
                                    $confidence = number_format((float)$valid_count / $total_count, 2, '.', '');        
                                    $match["score"] = round( $confidence * 100 );
                                }
                          
                                unset($match_vals["caption"]);
                                $match_vals = array_merge(["ID"=>$person_refs], $match_vals);
                                
                           
                                if(!array_key_exists($rule,  $final_matches)){
                                    $final_matches[$rule] = [];
                                }
                                //if the item exists under the rule, check if the score is greater - switch only than (not relevant for ["possible_same_person_gn","possible_same_person_fn"]
                                if(array_key_exists($person_refs_sql,  $final_matches[$rule]) &&
                                    !in_array($rule,["possible_same_person_gn","possible_same_person_fn"])){
                                        $curr_score = $final_matches[$rule][$person_refs_sql]["score"];
                                        if($match["score"] > $curr_score){
                                            $final_matches[$rule][$person_refs_sql] = $match;
                                            $metadata_matches[$rule][$person_refs_sql] = $match_vals;
                                        }
                                        continue;
                                }
                                $final_matches[$rule][$person_refs_sql] = $match;
                                $metadata_matches[$rule][$person_refs_sql] = $match_vals;
                            }
                        }
                    }
                }
            }
        }
    }

    //arrange the values of the final_matches & metadata_matches to have array and not assosiative array of ids
    foreach($final_matches as $rule=>&$arr){
        $arr = array_values($arr);
    }

    $final_matches = accumulateMatches($final_matches, $rule_arr);
    
    foreach($metadata_matches as $index=>&$data){
        foreach($data as $rule=>&$arr){
            $arr = array_values($arr);
        }
    }
    
    return ["final_matches" => $final_matches, "metadata" => $metadata_matches];
}

function accumulateMatches($final_matches, $rule_arr){
    $res = [];
    //if its not an array - return empty;
    if(!is_array($final_matches)){
        return [];
    }

    foreach($final_matches as $rule=>$matches){
        foreach($matches as $match){
            $accum_field = $rule_arr[$rule]["accum_field"] ?? $rule; 
            if(!array_key_exists($accum_field, $res)){
                $res[$accum_field] = [];
            }
            $match_id = $match["ID"];
            $match_score = $match["score"] ?? 0;
            if(array_key_exists($match_id, $res[$accum_field])){
                $curr_item = $res[$accum_field][$match_id];
                if($match_score > $curr_item){
                    $res[$accum_field][$match_id] = $match;
                }
            }
            else{
                $res[$accum_field][$match_id] = $match;
            }
    }
    
        
    }
    $final_res = [];

    foreach($res as $rule=>$matches){
        $value = array_values($matches);     
        $final_res[$rule] = $value;           
    }
    
    
    return $final_res;
}

function sameGN($first_arr, $second_arr){
    $gn_1 = getElementForValidation($first_arr, "given_name");
    $gn_2 = getElementForValidation($second_arr, "given_name");
    
    if(strcmp($gn_1, $gn_2) === 0 && (!empty($gn_1) || !empty($gn_2))){
        return true;
    }
    return false;
}

function validKeysByRule($rule, $first_arr, $second_arr, $mutual_keys){
    if($rule == "kunya"){
        return kunyaValidation($first_arr, $second_arr);
    }
    if($rule == "possible_same_person_arab"){
        return possible_same_person_arab_Validation($first_arr, $second_arr);     
    }
    if($rule == "possible_same_person_Chinese"){
        return possible_same_person_Asian_Validation($first_arr, $second_arr, "chinese");
    }
    if($rule == "possible_same_person_Korean"){
        return possible_same_person_Asian_Validation($first_arr, $second_arr, "korean");
    }
    if($rule == "possible_same_person_vietnamese"){
        return possible_same_person_Asian_Validation($first_arr, $second_arr, "vietnamese");
    }
    if($rule == "possible_son_father_arab"){
        return possible_son_father_arab_Validation($first_arr, $second_arr, $mutual_keys);
    }
    if($rule == "possible_father_son_arab"){
        return possible_father_son_arab_Validation($first_arr, $second_arr, $mutual_keys);
    }
    if($rule == "possible_father_son_somalian"){
        return possible_father_son_somalian_Validation($first_arr, $second_arr, $mutual_keys);
    }
}





function getElementForValidation($arr, $field){
    
    //if its caption&instance
    if(is_array($arr[$field] ?? null)){
        $caption = $arr[$field]["caption"];
        $instance = implode('^', $arr[$field]["instance_arr"]) ?? null;
    }
    else{
        $element_arr = explode("=>", $arr[$field] ?? "");
        $caption = $element_arr[0] ?? null;
        $instance = $element_arr[1] ?? null;
    }
    $ret = $instance ?? $caption;
    return $ret;
}

/**
 * special validation for kunya
 * @param unknown $first_arr
 * @param unknown $second_arr
 * @return number|boolean
 */
function kunyaValidation($first_arr, $second_arr){
    //1 - son = father_patrimonyal_name
    $first_son_element = getElementForValidation($first_arr, "son");
    $second_son_element = getElementForValidation($second_arr, "son");
    $first_fpn_element = getElementForValidation($first_arr, "father_patrimonyal_name");
    $second_fpn_element = getElementForValidation($second_arr, "father_patrimonyal_name");
    
    //2 gn=gn OR fn=fn
    $first_gn_element = getElementForValidation($first_arr, "given_name");
    $second_gn_element = getElementForValidation($second_arr, "given_name");
    $first_fn_element = getElementForValidation($first_arr, "family_name");
    $second_fn_element = getElementForValidation($second_arr, "family_name");
    
    
    if(($first_gn_element == $second_gn_element || $first_fn_element == $second_fn_element) && 
        $first_son_element == $second_fpn_element || $second_son_element == $first_fpn_element){
        return 2;
    }
    return false;
}

/**
 * special care for arab validation
 * @param unknown $first_arr
 * @param unknown $second_arr
 * @return boolean
 */
function possible_same_person_arab_Validation($first_arr, $second_arr){
    //1 
    $first_fn_element = getElementForValidation($first_arr, "family_name");
    $first_cn_element = getElementForValidation($first_arr, "clan_name");
    $first_tn_element = getElementForValidation($first_arr, "tribal_name");
    $first_gn_element = getElementForValidation($first_arr, "given_name");
    $first_fpn_element = getElementForValidation($first_arr, "father_patrimonyal_name");
    
    //2
    $second_fn_element = getElementForValidation($second_arr, "family_name");
    $second_cn_element = getElementForValidation($second_arr, "clan_name");
    $second_tn_element = getElementForValidation($second_arr, "tribal_name");
    $second_gn_element = getElementForValidation($second_arr, "given_name");
    $second_fpn_element = getElementForValidation($second_arr, "father_patrimonyal_name");
    
    if((in_array($first_fn_element, [$second_fn_element, $second_cn_element, $second_tn_element]) ||
        in_array($second_fn_element, [$first_fn_element, $first_cn_element, $first_tn_element])) &&
        ($first_gn_element == $second_gn_element && $first_fpn_element == $second_fpn_element)){
        return 3;
    }
    return false; 
}

/**
 * 
 * @param unknown $first_arr
 * @param unknown $second_arr
 */
function possible_same_person_Asian_Validation($first_arr, $second_arr, $asian_eth){
    //1
    $first_ckfn_element = getElementForValidation($first_arr, "chinese_korean_family_name");
    $first_cgnp1_element = getElementForValidation($first_arr, $asian_eth."_given_name_part_1");
    $first_cgnp2__element = getElementForValidation($first_arr, $asian_eth."_given_name_part_2");
    $first_ckgn_element = $asian_eth == "vietnamese" ? getElementForValidation($first_arr, "given_name")
                              : getElementForValidation($first_arr, "chinese_korean_given_name");
    
    //2
    $second_ckfn_element = getElementForValidation($second_arr, "chinese_korean_family_name");
    $second_cgnp1_element = getElementForValidation($second_arr, $asian_eth."_given_name_part_1");
    $second_cgnp2_element = getElementForValidation($second_arr, $asian_eth."_given_name_part_2");
    $second_ckgn_element = $asian_eth == "vietnamese" ? getElementForValidation($second_arr, "given_name")
    : getElementForValidation($second_arr, "chinese_korean_given_name");
    
    $first_cond = ($first_ckfn_element == $second_ckfn_element) && ($first_cgnp1_element == $second_cgnp1_element)
                    && ($first_cgnp2__element == $second_cgnp2_element);
    
    if($first_cond){
        //check we dont deal with empty fields
        if(!(empty($first_ckfn_element) && empty($second_ckfn_element)) 
            && !(empty($first_cgnp1_element)  && empty($second_cgnp1_element))
            && !(empty($first_cgnp2_element)  && empty($second_cgnp2_element))){
                return 3;            
        }
    }
    
    $second_cond = ($first_ckfn_element == $second_ckfn_element) && ($first_ckgn_element == $second_ckgn_element);
    if($second_cond){
        //check we dont deal with empty fields 
        if(!(empty($first_ckfn_element) && empty($second_ckfn_element))
            && !(empty($first_ckgn_element)  && empty($second_ckgn_element))){
                return 2;
        }
    }
    return false;
    
}

/**
 * possible_son_father_arab_Validation - special validation
 * @param unknown $first_arr
 * @param unknown $second_arr
 * @param unknown $first_element_ref
 * 
 * Son to Father:
 *  GN-son=FPT-father,
 *  FN-son=Fn-father
 */
function possible_son_father_arab_Validation($first_arr, $second_arr, $mutual_keys){
    $son_arr = $first_arr;
    $father_arr = $second_arr;
    $total = count($mutual_keys);
  
    //1 - son = father_patrimonyal_name
    $son_gn_element = getElementForValidation($son_arr, "given_name");
    $son_fpn_element = getElementForValidation($son_arr, "father_patrimonyal_name");
    $son_fn_element = getElementForValidation($son_arr, "family_name");
    
    //2 gn=gn OR fn=fn
    $father_fpn_element = getElementForValidation($father_arr, "father_patrimonyal_name");
    $father_gfpn_element = getElementForValidation($father_arr, "grandfather_patrimonyal_name");
    $father_fn_element = getElementForValidation($father_arr, "family_name");
    
    
    $first_cond = ($son_gn_element == $father_fpn_element) && ($son_fn_element == $father_fn_element);
    if($first_cond){
        //check we dont deal with empty fields
        return $total;
    }    
    return 0;
}

/**
 * possible_father_son_arab_Validation - special validation
 * @param unknown $first_arr
 * @param unknown $second_arr
 * @param unknown $first_element_ref
 * 
 * GN-father=FPT-son
 * FN-father=FN-son
 */
function possible_father_son_arab_Validation($first_arr, $second_arr, $mutual_keys){
    $son_arr = $first_arr;
    $father_arr = $second_arr;
    $total = count($mutual_keys);

    //1 - son = father_patrimonyal_name
    $father_gn_element = getElementForValidation($father_arr, "given_name");
    $father_fpn_element = getElementForValidation($father_arr, "father_patrimonyal_name");
    $father_fn_element = getElementForValidation($father_arr, "family_name");
    
    //2 gn=gn OR fn=fn
    $son_fpn_element = getElementForValidation($son_arr, "father_patrimonyal_name");
    $son_gfpn_element = getElementForValidation($son_arr, "grandfather_patrimonyal_name");
    $son_fn_element = getElementForValidation($son_arr, "family_name");
 
    $first_cond = ($father_gn_element == $son_fpn_element) && ($father_fn_element == $son_fn_element);
    if($first_cond){
        //check we dont deal with empty fields
        return $total;
    }
    return 0;
    
}

/**
 * possible_father_son_arab_Validation - special validation
 * @param unknown $first_arr
 * @param unknown $second_arr
 * @param unknown $first_element_ref
 *
 * GN-father=FPT-son
 * FN-father=FN-son
 */
function possible_father_son_somalian_Validation($first_arr, $second_arr, $mutual_keys){
    $son_arr = $first_arr;
    $father_arr = $second_arr;
    $total = count($mutual_keys);
    
    //1 - son = father_patrimonyal_name
    $first_gn_element = getElementForValidation($father_arr, "given_name");
    $first_fpn_element = getElementForValidation($father_arr, "father_patrimonyal_name");
    $first_gfpn_element = getElementForValidation($father_arr, "grandfather_patrimonyal_name");
    
    //2 gn=gn OR fn=fn
    $second_gn_element = getElementForValidation($son_arr, "given_name");
    $second_fpn_element = getElementForValidation($son_arr, "father_patrimonyal_name");
    $second_gfpn_element = getElementForValidation($son_arr, "grandfather_patrimonyal_name");
    
    $first_cond_a = ($first_fpn_element == $second_gn_element);
    $first_cond_b =  ($first_gfpn_element == $second_fpn_element);
    
    $second_cond_a = ($second_fpn_element == $first_gn_element);
    $second_cond_b =  ($second_gfpn_element == $first_fpn_element);
    
    if($first_cond_a && $first_cond_b || $second_cond_a && $second_cond_b){
        //check we dont deal with empty fields
        return $total;
    }
    return 0;
    
}



/**
 * validateValues - validate no different exists values in match&person data
 * @param unknown $match_vals
 * @param unknown $person_data
 * @return unknown
 */
function validateValues($mutual_keys, $first_arr, $second_arr, $mand_keys, $mapped_cols = []){
    $total_match = 0;
    $first_caption = $second_caption = "";
    foreach ($mutual_keys as $col){
        $mapped_col = checkMappedCols($mapped_cols, $col);
        $first_element_arr = explode("=>", $first_arr[$col] ?? "");
        $first_caption = $first_element_arr[0] ?? null;
        $first_instance = $first_element_arr[1] ?? null;
        
        //if one field appear in one array, but not in the other one - continue
        if((array_key_exists($col, $first_arr) && !array_key_exists($col, $second_arr)) ||
            (!array_key_exists($col, $first_arr) && array_key_exists($col, $second_arr))){
                continue;
        }
        //if its caption&instance
        if(is_array($second_arr[$col])){
            $second_caption = $second_arr[$col]["caption"] ?? null;
            $second_instance = implode('^', $second_arr[$col]["instance_arr"]) ?? null;
        }
        else{
            $second_element_arr = explode("=>", $second_arr[$col] ?? null);
            $second_caption = $second_element_arr[0] ?? null;
            $second_instance = $second_element_arr[1] ?? null;
        }
        $first_element = $first_instance ?? $first_caption;
        $second_element = $second_instance ?? $second_caption;
        
        
        //if its full match (also if its 2 initials full match) - +1 point
        if($first_element == $second_element){
            $total_match++;
        }
        //if its initials match but not just 1 letter words - +0.5 point
        elseif((!empty($first_caption) && !empty($second_caption) && $first_caption[0] == $second_caption[0] && (strlen($first_caption) >1) || strlen($second_caption) >1)){
            $total_match = $total_match+0.5;
        }
        
        elseif(in_array($col, $mand_keys)){
            //if its mandatory column - return 0 - no match
            return 0;
        }
        else{
            //if there is no match for optional - continue to next nc
            continue;
        }
        
    }
    
    return $total_match;
}


/**
 *checkMandatoryFields
 */
function checkMandatoryFields($na, $mandatory_arr){
    $exists = false;
    foreach($mandatory_arr as $f){
        if(!empty($na[$f])){
            $exists = true;
            break;
        }
    }
    return $exists;
}

/**
 *checkAllMandatoryFields
 */
function checkAllMandatoryFields($na, $mandatory_arr){
    $exists = true;
    foreach($mandatory_arr as $f){
        if(empty($na[$f])){
            $exists = false;
            break;
        }
    }
    return $exists;
}
