middleware('auth'); $this->_service = 'metric'; $this->_module = 'metric_report'; $this->_viewname = 'metricreport'; $this->_title = 'Metric Reports'; $this->_base_url = '/metricreport'; } public function list(Request $request) { $response = LambdaRequest::signedrequest('get', $this->_service, $this->_module.'/list'); //echo '
'; print_r($response); exit;
        $fields = $this->get_list_fields();
        return $this->view('list')->with([
            'title' => $this->_title,
            'fields' => $fields,
            'base_url' => $this->_base_url,
            'items' => $response->data->items,
            'buttons' => $this->get_list_buttons()
        ]);
    }

    protected function get_list_fields(){
        return [
            'actions' => ['title' => 'Actions', 'buttons' => [ 'report' => ['icon' => 'chart-bar', 'querystring' => 'id={ID}'] ] ],
            'name' => ['title' => 'Name', 'type' => 'text'],
            'type' => ['title' => 'Type', 'type' => 'text'],
            'validity_start' => ['title' => 'Validity start', 'type' => 'date'],
            'validity_end' => ['title' => 'Validity end', 'type' => 'date'],
            'agg_type' => ['title' => 'Aggregation type', 'type' => 'text'],            
        ];
    }

    public function report(Request $request) {
        $post = $request->except('_token');
        //echo '
';print_r($post); exit;
        $response = LambdaRequest::signedrequest('post', $this->_service, $this->_module.'/view', $post, 300);
        if($post['type'] == 'incremental') {
            //echo '
'; print_r($response->data); print_r($post); exit;
        }
        //echo '
'; print_r($response->data); print_r($post); exit;
        $colors = ['FECD00', '01C14B', 'FF8050', '4A5CD0', '707070'];
        $breadcrumbs = [];
        $isTeamReport = isset($response->data->graph->agg_type) && $response->data->graph->agg_type === 'team';
        if ($isTeamReport && isset($post['hid'])) {
            if($request->session()->has('leaderboard_breadcrumbs')) {
                $breadcrumbs = $request->session()->get('leaderboard_breadcrumbs');
            }
            $breadcrumbs[$post['level']] = ['hid' => $post['hid'], 'username' => $post['username'], 'level' => $post['level'] ];
            $request->session()->put('leaderboard_breadcrumbs', $breadcrumbs);
            $breadcrumbs = array_filter($breadcrumbs, function($k) use($post) { return $k >= $post['level']; }, ARRAY_FILTER_USE_KEY);
            krsort($breadcrumbs);
        }
        $post = array_merge((array)$response->data->post,$post);
        if (isset($post['metrics']) && is_string($post['metrics'])) {
            $post['metrics'] = array_values(array_filter(
                explode(',', $post['metrics']),
                function ($m) { return trim((string) $m) !== ''; }
            ));
        } elseif (isset($post['metrics']) && is_array($post['metrics'])) {
            $post['metrics'] = array_values(array_filter(
                $post['metrics'],
                function ($m) { return trim((string) $m) !== ''; }
            ));
        }
        if (isset($response->data->graph->metrics) && is_array($response->data->graph->metrics)) {
            $selectedMetrics = (!empty($post['metrics']) && is_array($post['metrics'])) ? $post['metrics'] : [];

            $allMetricFieldsMissingOrEmpty = false;
            foreach ($response->data->graph->metrics as $metric) {
                if (is_object($metric)) {
                    if (!isset($metric->metric) || $metric->metric === '' || $metric->metric === null) {
                        $allMetricFieldsMissingOrEmpty = true;
                        break;
                    }
                } elseif (is_array($metric)) {
                    if (!isset($metric['metric']) || $metric['metric'] === '' || $metric['metric'] === null) {
                        $allMetricFieldsMissingOrEmpty = true;
                        break;
                    }
                }
            }

            $showAllMetrics = empty($selectedMetrics) || $allMetricFieldsMissingOrEmpty;

            foreach ($response->data->graph->metrics as &$metric) {
                if ($showAllMetrics) {
                    if (is_object($metric)) {
                        $metric->is_visible = true;
                    } elseif (is_array($metric)) {
                        $metric['is_visible'] = true;
                    }
                } else {
                    if (is_object($metric)) {
                        $metric->is_visible = isset($metric->metric)
                            ? in_array($metric->metric, $selectedMetrics)
                            : false;
                    } elseif (is_array($metric)) {
                        $metric['is_visible'] = isset($metric['metric'])
                            ? in_array($metric['metric'], $selectedMetrics)
                            : false;
                    }
                }
            }
            unset($metric);

            if (isset($response->data->graph->values->metrics) && is_array($response->data->graph->values->metrics)) {
                foreach ($response->data->graph->values->metrics as &$metric) {
                    if ($showAllMetrics) {
                        if (is_object($metric)) {
                            $metric->is_visible = true;
                        } elseif (is_array($metric)) {
                            $metric['is_visible'] = true;
                        }
                    } else {
                        if (is_object($metric)) {
                            $metric->is_visible = isset($metric->metric)
                                ? in_array($metric->metric, $selectedMetrics)
                                : false;
                        } elseif (is_array($metric)) {
                            $metric['is_visible'] = isset($metric['metric'])
                                ? in_array($metric['metric'], $selectedMetrics)
                                : false;
                        }
                    }
                }
                unset($metric);
            }
        }

        if (isset($response->data->graph)) {
            $this->normalizeLeaderboardMeRow($response->data->graph);
        }

        $contact_attribute_labels = [];
        if (isset($response->data->graph->contact_attributes) && is_array($response->data->graph->contact_attributes)) {
            $contact_attribute_labels = $this->resolveContactAttributeLabels($response->data->graph->contact_attributes);
        }

        $user_attribute_labels = [];
        if (isset($response->data->graph)) {
            $user_attribute_labels = $this->resolveUserAttributeLabels($this->userAttributeCodes($response->data->graph));
        }
        
        //echo '
'; print_r(['periods' => $response->data->periods, 'charts' => $response->data->available_charts, 'graph' => $response->data->graph, 'post' => $post, 'colors' => $colors, 'breadcrumbs' => $breadcrumbs]); exit;
        return $this->view('report')->with(['periods' => $response->data->periods, 'charts' => $response->data->available_charts, 'graph' => $response->data->graph, 'post' => $post , 'colors' => $colors, 'breadcrumbs' => $breadcrumbs, 'contact_attribute_labels' => $contact_attribute_labels, 'user_attribute_labels' => $user_attribute_labels]);
    }

    public function export(Request $request) {
        $post = $request->except('_token');
        $post['export'] = 1;
        $response = LambdaRequest::signedrequest('post', $this->_service, $this->_module.'/view', $post, 300);
        //echo '
'; print_r($response); print_r($post); exit;
        if (isset($response->data->graph)) {
            $this->normalizeLeaderboardMeRow($response->data->graph);
        }
        $post = (array)$response->data->post;
        $exceldata = [];
        $exceldata[] = [$response->data->graph->name];
        $exceldata[] = ['Report: '.ucwords($response->data->graph->agg_type).' Report'];
        $exceldata[] = ['Type: '.ucwords($response->data->graph->type).' Metric'];
        foreach($response->data->periods as $v) {
            if($post['period'] == $v->value) {
                $exceldata[] = ['Period: '.ucwords($v->label)];
            }
        }
        $exceldata[] = [''];
        $userAttrCodes = $this->userAttributeCodes($response->data->graph);
        $userAttrLabels = $this->resolveUserAttributeLabels($userAttrCodes);
        switch($response->data->post->type) {
            case 'leaderboard':
            case 'scoreboard':
                $isTeamReport = isset($response->data->graph->agg_type) && $response->data->graph->agg_type === 'team';
                $hideRank = $isTeamReport && ($post['type'] ?? '') === 'leaderboard';
                $headings = $hideRank
                    ? ["User Id", "User Name", "Employee Code", "Designation"]
                    : ["Rank", "User Id", "User Name", "Employee Code", "Designation"];
                foreach ($userAttrCodes as $attr) {
                    $headings[] = $userAttrLabels[$attr] ?? ucwords(str_replace('_', ' ', (string) $attr));
                }
                //'Manager 1 Name', 'Manager 1 Emp Code', 'Manager 1 Email', 'Manager 2 Name', 'Manager 2 Emp Code', 'Manager 2 Email'
                $parentSample = [];
                if (!empty($response->data->graph->values)) {
                    foreach ($response->data->graph->values as $val) {
                        if (isset($val->user->parents) && !empty((array) $val->user->parents)) {
                            $parentSample = (array) $val->user->parents;
                            break;
                        }
                    }
                }
                foreach ($parentSample as $par) {
                    $headings = array_merge($headings, ['Manager '.$par->level.' Name', 'Manager '.$par->level.' Emp Code']);
                }
                $headings = array_merge($headings, ['Zone', 'Region', "Area", "Territory", "Active User"]);
                //echo '
'; print_r($headings); exit;
                if(count($response->data->graph->values) > 0 && isset($response->data->graph->values[0]->stats->prescribers) ){
                    $headings[] = "Prescribers";
                }
                foreach($response->data->graph->metrics as $val) {
                    $headings[] = $val->display;
                }
                $exceldata[] = $headings;
                foreach($response->data->graph->values as $val) {
                    $user = $val->user ?? null;
                    $rowdata = $hideRank
                        ? [
                            (string)($user->id ?? ''),
                            (string)($user->name ?? ''),
                            (string)($user->employee_code ?? ''),
                            $user->designation ?? '',
                        ]
                        : [
                            (string)($val->rank ?? ''),
                            (string)($user->id ?? ''),
                            (string)($user->name ?? ''),
                            (string)($user->employee_code ?? ''),
                            $user->designation ?? '',
                        ];
                    foreach ($userAttrCodes as $attr) {
                        $rowdata[] = $this->userAttributeValue($user, $attr);
                    }
                    $parents = (isset($user->parents) && !empty((array) $user->parents)) ? (array) $user->parents : [];
                    foreach ($parents as $par) {
                        $rowdata[] = isset($par->name) ? $par->name : '-';
                        $rowdata[] = isset($par->employee_code) ? $par->employee_code : '-';
                        //$rowdata[] = isset($par->email) ? $par->email : '-';
                    }
                    for ($i = count($parents); $i < count($parentSample); $i++) {
                        $rowdata[] = '-';
                        $rowdata[] = '-';
                    }
                    // $rowdata[] = isset($user->manager1->name) ? $user->manager1->name : '-';
                    // $rowdata[] = isset($user->manager1->employee_code) ? $user->manager1->employee_code : '-';
                    // $rowdata[] = isset($user->manager1->email) ? $user->manager1->email : '-';
                    // $rowdata[] = isset($user->manager2->name) ? $user->manager2->name : '-';
                    // $rowdata[] = isset($user->manager2->employee_code) ? $user->manager2->employee_code : '-';
                    // $rowdata[] = isset($user->manager2->email) ? $user->manager2->email : '-';

                    $rowdata[] = isset($user->positions->Zone) ? $user->positions->Zone : (isset($user->positions->Country) ? $user->positions->Country : '-' );
                    $rowdata[] = isset($user->positions->Region) ? $user->positions->Region : '-';
                    $rowdata[] = isset($user->positions->Area) ? $user->positions->Area : '-';
                    $rowdata[] = isset($user->positions->Territory) ? $user->positions->Territory : '-';

                    $stats = $val->stats ?? null;
                    $rowdata[] = isset($stats->ucount) ? $stats->ucount : 0;

                    if (isset($stats->prescribers)) {
                        $rowdata[] = $stats->prescribers;
                    }
                    foreach($response->data->graph->metrics as $m) {
                        $rowdata[] = $this->leaderboardStatValue($stats, $m);
                    }
                    $exceldata[] = $rowdata;
                }
                break;
            case 'trend':
                $headings = ['Periods'];
                if($response->data->graph->type == 'grouped') {
                    foreach($response->data->graph->values as $met) {
                        $headings[] = $met->metric;
                    }
                    $exceldata[] = $headings;
                    $periodStats = $response->data->graph->values[0]->stats ?? [];
                    foreach($periodStats as $i => $stat) {
                        $row = [$stat->x];
                        foreach($response->data->graph->values as $met) {
                            $row[] = isset($met->stats[$i])?$met->stats[$i]->y:0;
                        }
                        $exceldata[] = $row;
                    }
                } else {
                    $headings[] = $response->data->graph->label;
                    $exceldata[] = $headings;
                    foreach($response->data->graph->values as $i => $val) {
                        $exceldata[] = [$val->x, $val->y];
                    }
                }
                break;
            case 'graphical':
                if($response->data->graph->type == 'grouped') {
                    $exceldata[] = ['Metric Name', 'Units', 'Percent'];
                    $total = 0; 
                    foreach($response->data->graph->values as $val) {
                        $total = $total + $val->value;
                    }
                    foreach($response->data->graph->values as $val) {
                        $exceldata[] = [$val->label, $val->value, (string)round(($val->value/$total)*100, 2)];
                    }
                }
                break;
            case 'details':
                if($response->data->graph->chart == 'tabular') {
                    $headers = ['User', 'Employee Code', 'Email', 'Designation'];
                    foreach ($userAttrCodes as $attr) {
                        $headers[] = $userAttrLabels[$attr] ?? ucwords(str_replace('_', ' ', (string) $attr));
                    }
                    $headers = array_merge($headers, ['Manager 1 Name', 'Manager 1 Emp Code', 'Manager 1 Email', 'Manager 2 Name', 'Manager 2 Emp Code', 'Manager 2 Email',  'Zone', 'Region', "Area", "Territory", "Role"]);
                    foreach($response->data->graph->values->metrics as $metric) {
                        $headers[] = $metric->metric;
                    }
                    $exceldata[] = $headers;
                    foreach($response->data->graph->values->users as $user) {
                        $row = [];
                        $row[] = $user->name;
                        $row[] = $user->employee_code;
                        $row[] = $user->email;
                        $row[] = $user->designation;
                        foreach ($userAttrCodes as $attr) {
                            $row[] = $this->userAttributeValue($user, $attr);
                        }

                        if(isset($user->parents->{'level_'.($user->level+1)})) {
                            $manager = $user->parents->{'level_'.($user->level+1)};
                            $row[] = isset($manager->name) ? $manager->name : '-';
                            $row[] = isset($manager->employee_code) ? $manager->employee_code : '-';
                            $row[] = isset($manager->email) ? $manager->email : '-';
                        } else {
                            $row[] = '-';
                            $row[] = '-';
                            $row[] = '-';
                        }
                        if(isset($user->parents->{'level_'.($user->level+2)})) {
                            $manager = $user->parents->{'level_'.($user->level+2)};
                            $row[] = isset($manager->name) ? $manager->name : '-';
                            $row[] = isset($manager->employee_code) ? $manager->employee_code : '-';
                            $row[] = isset($manager->email) ? $manager->email : '-';
                        } else {
                            $row[] = '-';
                            $row[] = '-';
                            $row[] = '-';
                        }

                        // $row[] = isset($user->manager1->name) ? $user->manager1->name : '-';
                        // $row[] = isset($user->manager1->employee_code) ? $user->manager1->employee_code : '-';
                        // $row[] = isset($user->manager1->email) ? $user->manager1->email : '-';
                        // $row[] = isset($user->manager2->name) ? $user->manager2->name : '-';
                        // $row[] = isset($user->manager2->employee_code) ? $user->manager2->employee_code : '-';
                        // $row[] = isset($user->manager2->email) ? $user->manager2->email : '-';

                        $row[] = isset($user->positions->Zone) ? $user->positions->Zone : '-';
                        $row[] = isset($user->positions->Region) ? $user->positions->Region : '-';
                        $row[] = isset($user->positions->Area) ? $user->positions->Area : '-';
                        $row[] = isset($user->positions->Territory) ? $user->positions->Territory : '-';
                        $row[] = isset($user->roles) ? (is_array($user->roles) ? implode(',', $user->roles) : $user->roles) : '-';
                        foreach($response->data->graph->values->metrics as $metric) {
                            $row[] = isset($metric->stats->{$user->id}) ? $metric->stats->{$user->id} : 0;
                        }
                        $exceldata[] = $row;
                    }
                }
                break;
            case 'contacts':
                if($response->data->graph->chart == 'contacts') {
                    //echo '
'; print_r($response->data->graph->values); exit;

                    $attrLabels = [];
                    if (isset($response->data->graph->contact_attributes) && is_array($response->data->graph->contact_attributes)) {
                        $attrLabels = $this->resolveContactAttributeLabels($response->data->graph->contact_attributes);
                    }

                    $headers = ['Doctor', 'MSL Code'];
                    foreach($response->data->graph->contact_attributes as $attr) {
                        $headers[] = $attrLabels[$attr] ?? ucwords($attr);
                    }
                    $headers = array_merge($headers, ['User', 'Employee Code', 'Email', 'Designation', 'Manager 1 Name', 'Manager 1 Emp Code', 'Manager 1 Email', 'Manager 2 Name', 'Manager 2 Emp Code', 'Manager 2 Email',  'Zone', 'Region', "Area", "Territory"]);
                    foreach($response->data->graph->values->metrics as $metric) {
                        $headers[] = $metric->metric;
                    }
                    $exceldata[] = $headers;
                    foreach($response->data->graph->values->contacts as $contact) {
                        $row = [];
                        $row[] = $contact->name;
                        $row[] = $contact->msl_code;

                        foreach($response->data->graph->contact_attributes as $attr) {
                            $row[] = isset($contact->{$attr}) ? $contact->{$attr} : '';
                        }
                        if(!isset($response->data->graph->values->users->{$contact->id})) {
                            continue;
                        }

                        $user = $response->data->graph->values->users->{$contact->id};
                        $row[] = $user->name;
                        $row[] = $user->employee_code;
                        $row[] = $user->email;
                        $row[] = $user->designation;

                        $row[] = isset($user->manager1->name) ? $user->manager1->name : '-';
                        $row[] = isset($user->manager1->employee_code) ? $user->manager1->employee_code : '-';
                        $row[] = isset($user->manager1->email) ? $user->manager1->email : '-';
                        $row[] = isset($user->manager2->name) ? $user->manager2->name : '-';
                        $row[] = isset($user->manager2->employee_code) ? $user->manager2->employee_code : '-';
                        $row[] = isset($user->manager2->email) ? $user->manager2->email : '-';

                        $row[] = isset($user->positions->Zone) ? $user->positions->Zone : '-';
                        $row[] = isset($user->positions->Region) ? $user->positions->Region : '-';
                        $row[] = isset($user->positions->Area) ? $user->positions->Area : '-';
                        $row[] = isset($user->positions->Territory) ? $user->positions->Territory : '-';

                        foreach($response->data->graph->values->metrics as $metric) {
                            $row[] = isset($metric->stats->{$contact->id}) ? $metric->stats->{$contact->id} : 0;
                        }
                        $exceldata[] = $row;
                    }
                }
                break;
            case 'incremental':
                if($response->data->graph->chart == 'incremental') {
                    $headers = ['User', 'Employee Code', 'Email', 'Designation', 'Manager 1 Name', 'Manager 1 Emp Code', 'Manager 1 Email', 'Manager 2 Name', 'Manager 2 Emp Code', 'Manager 2 Email',  'Zone', 'Region', "Area", "Territory", "Role"];
                    // foreach($response->data->graph->values->metrics as $metric) {
                    //     //$headers[] = $metric->metric;
                    // }
                    $graph = $response->data->graph;
                    $period = explode('-', $post['period'])[0];
                    $interval = 'P1D';
                    if($period == 'week') {
                        $interval = 'P1W';
                    } elseif($period == 'month') {
                        $interval = 'P1M';
                    }

                    $first_day = strtotime($graph->first_day);
                    $last_day = strtotime($graph->last_day);

                    $start    = new \DateTime($graph->first_day);
                    $end      = new \DateTime($graph->last_day);
                    $interval = new \DateInterval($interval);
                    $periods   = new \DatePeriod($start, $interval, $end);
                    $colspan = 0;
                    foreach($periods as $date) {
                        $colspan++;
                    }
                    $subheaders = ["","","","","","","","","","","","","","",""];
                    foreach($graph->values->metrics as $metric){
                        $headers[] = $metric->metric;
                        //$headers = array_merge($headers, Array($colspan-1).fill(""));
                        foreach($periods as $date) {
                            $subheaders[] = $date->format('d M Y');
                            $headers[] = "";
                        }
                        $subheaders[] = "";
                        //unset($headers[sizeof($headers)-1]);
                    }

                    $exceldata[] = $headers;
                    $exceldata[] = $subheaders;
                    foreach($response->data->graph->values->users as $user) {
                        $row = [];
                        $row[] = $user->name;
                        $row[] = $user->employee_code;
                        $row[] = $user->email;
                        $row[] = $user->designation;

                        $row[] = isset($user->manager1->name) ? $user->manager1->name : '-';
                        $row[] = isset($user->manager1->employee_code) ? $user->manager1->employee_code : '-';
                        $row[] = isset($user->manager1->email) ? $user->manager1->email : '-';
                        $row[] = isset($user->manager2->name) ? $user->manager2->name : '-';
                        $row[] = isset($user->manager2->employee_code) ? $user->manager2->employee_code : '-';
                        $row[] = isset($user->manager2->email) ? $user->manager2->email : '-';

                        $row[] = isset($user->positions->Zone) ? $user->positions->Zone : '-';
                        $row[] = isset($user->positions->Region) ? $user->positions->Region : '-';
                        $row[] = isset($user->positions->Area) ? $user->positions->Area : '-';
                        $row[] = isset($user->positions->Territory) ? $user->positions->Territory : '-';
                        $row[] = isset($user->roles) ? (is_array($user->roles) ? implode(',', $user->roles) : $user->roles) : '-';
                        
                        foreach($graph->values->metrics as $metric) {
                            foreach($periods as $date) {
                                $row[] = isset($metric->stats->{$user->id}->{$date->getTimestamp().'000'}) ? $metric->stats->{$user->id}->{$date->getTimestamp().'000'} : '-';
                            }
                            $row[] = "";
                        }
                        // foreach($response->data->graph->values->metrics as $metric) {
                        //     //$row[] = isset($metric->stats->{$user->id}) ? $metric->stats->{$user->id} : '-';
                        // }
                        $exceldata[] = $row;
                    }
                }
                break;

        }
        //echo '
'; print_r($exceldata); exit;
        if(isset($post['email']) && $post['email'] == 1) {
            $data = new \StdClass;
            $data->sender_name = 'Rapport Support';
            $data->sender_email = 'support1@stratawiz.com';
            $data->subject = 'Attached Report';
            $data->body = '';

            $report = Excel::raw(new InvoicesExport($exceldata), 'Xlsx');
            $data->attachment = $report;
            $data->attachment_name = 'report.xlsx';

            Mail::to( $response->data->user->email )->send(new ReportExcel($data));
            //Mail::to( 'ravigulhane1983@gmail.com' )->send(new ReportExcel($data));
            return response()->json(['sent' => 'yes']);
        } elseif(isset($post['s3']) && $post['s3'] == 1) {
            $filename = 'reports/'.strtotime("now").'-report.xlsx';
            $res = Excel::store(new InvoicesExport($exceldata), $filename);
            Log::debug('https://did94hhhcgq1d.cloudfront.net/'.$filename);
            return response()->json(['sent' => 'yes', 'filename' => 'https://did94hhhcgq1d.cloudfront.net/'.$filename]);
        } else {
            return Excel::download(new InvoicesExport($exceldata), 'report.xlsx');
        }
    }
    
    // public function healthylungeducatordailyreporting(Request $request) {
    //     $post = $request->input();

    //     $params = [
    //         'partition' => 'rapport-pulmocare',
    //         'form_id' => '1713351143-9afc68f4-653f-491a-9e0e-a27d61ed1e07',
    //         'user_id' => Auth::user()->user_id
    //     ];
    //     $formDef = LambdaRequest::signedrequest('post', 'form', 'formentity/getformdefination', $params);
    //     $fields = [
    //         'actions' => ['title' => 'Actions', 'buttons' => ['report' => ['icon' => 'chart-bar', 'querystring' => 'id={ID}']]]
    //     ];
    //     if (isset($formDef->data->questions)) {
    //         foreach ($formDef->data->questions as $question) {
    //             $fields[$question->code] = [
    //                 'title' => $question->question,
    //                 'type' => isset($question->type) ? $question->type : 'text'
    //             ];
    //         }
    //     }
    //     //echo '
'; print_r($fields); exit;
    //     return view('healthylungeducatordailyreporting.list')->with([
    //         'title' => 'Healthy Lung Educator Daily reporting (Camp/ Clinic)',
    //         'fields' => $fields,
    //         'base_url' => $this->_base_url,
    //         'buttons' => [ ['title' => 'Export', 'link' => $this->_base_url . '/export'] ]
    //     ]);
    // }

    /**
     * Leaderboard stats may be keyed by metric id or by display/title (e.g. unique_new combined metrics).
     */
    protected function leaderboardStatValue($stats, $metric)
    {
        if (!$stats) {
            return 0;
        }
        $metricKey = is_object($metric) ? ($metric->metric ?? '') : ($metric['metric'] ?? '');
        $displayKey = is_object($metric) ? ($metric->display ?? '') : ($metric['display'] ?? '');
        if ($metricKey !== '' && isset($stats->{$metricKey})) {
            return $stats->{$metricKey};
        }
        if ($displayKey !== '' && isset($stats->{$displayKey})) {
            return $stats->{$displayKey};
        }
        return 0;
    }

    /**
     * API prepends a synthetic "Me (...)" row with score/rank only; merge full stats and drop duplicate.
     */
    protected function normalizeLeaderboardMeRow($graph)
    {
        if (!isset($graph->chart) || $graph->chart !== 'leaderboard') {
            return;
        }
        if (!isset($graph->values) || !is_array($graph->values) || count($graph->values) < 1) {
            return;
        }

        $first = $graph->values[0];
        if (!isset($first->user->name) || strpos($first->user->name, 'Me (') !== 0) {
            return;
        }

        $uid = $first->user->id ?? null;
        if (!$uid) {
            return;
        }

        $canonical = null;
        foreach ($graph->values as $val) {
            if (isset($val->user->id) && $val->user->id === $uid && isset($val->stats)) {
                $canonical = $val;
                break;
            }
        }

        if ($canonical) {
            if (!isset($first->stats)) {
                $first->stats = $canonical->stats;
            }
            foreach (['employee_code', 'positions', 'parents', 'designation', 'avatar', 'hierarchy'] as $prop) {
                if ((!isset($first->user->{$prop}) || $first->user->{$prop} === '' || $first->user->{$prop} === '-')
                    && isset($canonical->user->{$prop})) {
                    $first->user->{$prop} = $canonical->user->{$prop};
                }
            }
            foreach ($this->userAttributeCodes($graph) as $attr) {
                if ((!isset($first->user->{$attr}) || $first->user->{$attr} === '' || $first->user->{$attr} === '-')
                    && isset($canonical->user->{$attr})) {
                    $first->user->{$attr} = $canonical->user->{$attr};
                }
            }
        }

        $graph->values = array_values(array_filter($graph->values, function ($val, $i) use ($uid) {
            if ($i === 0) {
                return true;
            }
            return ($val->user->id ?? null) !== $uid;
        }, ARRAY_FILTER_USE_BOTH));
    }

    /**
     * Map contact attribute codes to display names.
     */
    protected function resolveContactAttributeLabels(array $codes): array
    {
        $labels = [];
        if (empty($codes)) {
            return $labels;
        }

        $map = [];
        try {
            $coattr = $this->getlambda('get', 'contact', 'contactattribute', 'get_all');
            if (isset($coattr->data->items) && is_array($coattr->data->items)) {
                foreach ($coattr->data->items as $coatt) {
                    if (isset($coatt->code)) {
                        $map[$coatt->code] = $coatt->attribute ?? $coatt->code;
                    }
                }
            }
        } catch (\Throwable $e) {
            // Fall back to ucwords(code) below
        }

        foreach ($codes as $code) {
            $labels[$code] = $map[$code] ?? ucwords(str_replace('_', ' ', (string) $code));
        }

        return $labels;
    }

    /**
     * Selected user attribute codes when the view is configured to show them.
     */
    protected function userAttributeCodes($graph): array
    {
        if (($graph->show_user_attributes ?? 'no') !== 'yes') {
            return [];
        }
        $raw = $graph->user_attributes ?? [];
        if (!is_array($raw)) {
            return [];
        }
        $codes = [];
        foreach ($raw as $code) {
            if (is_object($code)) {
                $code = $code->code ?? '';
            }
            $code = trim((string) $code);
            if ($code !== '') {
                $codes[] = $code;
            }
        }
        return array_values(array_unique($codes));
    }

    protected function userAttributeValue($user, string $attr): string
    {
        if (!$user) {
            return '-';
        }
        $prefixed = 'attribute_' . $attr;
        if (isset($user->{$attr}) && $user->{$attr} !== '') {
            return (string) $user->{$attr};
        }
        if (isset($user->{$prefixed}) && $user->{$prefixed} !== '') {
            return (string) $user->{$prefixed};
        }
        return '-';
    }

    /**
     * Map user attribute codes to display names.
     */
    protected function resolveUserAttributeLabels(array $codes): array
    {
        $labels = [];
        if (empty($codes)) {
            return $labels;
        }

        $map = [];
        try {
            $userAttrs = $this->getlambda('get', 'ums', 'userattribute', 'get_all');
            if (isset($userAttrs->data->items) && is_array($userAttrs->data->items)) {
                foreach ($userAttrs->data->items as $attr) {
                    if (isset($attr->code)) {
                        $map[$attr->code] = $attr->attribute ?? $attr->code;
                    }
                }
            }
        } catch (\Throwable $e) {
            // Fall back to ucwords(code) below
        }

        foreach ($codes as $code) {
            $labels[$code] = $map[$code] ?? ucwords(str_replace('_', ' ', (string) $code));
        }

        return $labels;
    }
}