<?php

namespace App\Http\Controllers\Admin\Api;

use App\Classes\Constant;
use App\Http\Controllers\Controller;
use App\Models\Admin;
use App\Models\Appointment;
use App\Models\Cart;
use App\Models\Item;
use App\Models\ItemHistory;
use App\Models\LabkitOrderItem;
use App\Models\LicenseNumberModel;
use App\Models\Patient;
use App\Models\PatientNote;
use App\Models\PatientPrescription;
use App\Models\ProfileQuestion;
use App\Models\Setting;
use App\Models\Telemedpro;
use DateInterval;
use DatePeriod;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use PhpParser\Node\Stmt\Const_;
use Illuminate\Auth\Access\AuthorizationException;

class ReportsController extends Controller
{
    protected $url;
    protected $user;
    public function __construct(UrlGenerator $url)
    {
        $this->url = $url;
        $this->user = Auth::guard('admin')->user();
    }
    public function providerReportFilters()
    {
        $providers = Telemedpro::select(
            DB::raw("CONCAT(license_numbers.license_number,',',license_numbers.state) as provider_license_number"),
            'appointments.patient_name',
            'appointments.appointment_date',
            'appointments.appointment_time',
            'appointments.timezone',
            'start_time',
            'end_time',
            'duration',
            DB::raw("CONCAT(patients.first_name,',',patients.last_name) as patient_name"),
            'patients.phone_no',
            'patients.email',
            'patients.address',
            'patients.city',
            'patients.state',
            'patients.zip_code',
            'patients.country',
            'patients.gender',
            'patients.dob',
            'patients.height',
            'patients.weight'
        )
            ->LeftJoin('license_numbers', 'provider_id', 'telemed_pros.id')
            ->LeftJoin('appointments', 'appointments.telemed_pros_id', 'telemed_pros.id')
            ->leftJoin('patients', 'appointments.patient_id', 'patients.id')
            ->whereNotNull('appointments.start_time')
            ->whereNotNull('appointments.end_time')
            ->get();

        foreach ($providers as $provider) {
            $start_datetime = new DateTime($provider->start_time);
            $diff = $start_datetime->diff(new DateTime($provider->end_time));
            $duration = $diff->h . " hours " . $diff->i . " Min";
            // dd($providers->duration,$duration);
            $provider->duration = $duration;
        }

        return response()->json([
            'provider_list' => $providers,
        ]);
    }
    public function providerReportPost(Request $request)
    {
        return response()->json([
            'provider_list' => ''
        ]);
    }
    public function overviewReport(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'overview_analytics', new ProfileQuestion);
            $start_date = $request->get('start_date');
            $end_date = $request->get('end_date');
            $totalOrdersStats = Cart::select(
                DB::raw("sum(case when carts.status = 'completed' then 1 else 0 end) as total_sales"),
                DB::raw("sum(case when carts.status = 'completed' then carts.total_amount else 0 end) as sales_amount"),
                DB::raw("count(items.id) as products_sold")
            )
                ->Join('items', 'items.cart_id', 'carts.id')
                ->where('carts.created_at', '>=', $start_date . " 00:00:00")
                ->where('carts.created_at', '<=', $end_date . " 23:59:59")
                ->where('carts.status', '=', 'completed')
                ->get();
            $orderCollection = Cart::select(
                'carts.id as order_id',
                'carts.status',
                'carts.email',
                'carts.total_amount',
                'carts.created_at as date',
                DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name")
            )
                ->where('carts.created_at', '>=', $start_date . " 00:00:00")
                ->where('carts.created_at', '<=', $end_date . " 23:59:59")
                ->where('carts.status', '=', 'completed')
                ->get();
            $orderData = $orderCollection->map(function ($query, $key) {
                $patientType = $query->where('email', $query->email)->count();
                $itemSold = Item::select(DB::raw("GROUP_CONCAT(title SEPARATOR ', ') as items"))
                    ->where('cart_id', $query->order_id)
                    ->leftJoin('plans_v1', 'items.plans_id', 'plans_v1.id');
                $itemCount = $itemSold->count();
                $products = $itemSold->first();
                if ($patientType > 1)
                    $query->customer_type = 'returning';
                else
                    $query->customer_type = 'new';

                $query->products = $products->items ?? null;
                $query->item_sold = $itemCount ?? 0;

                $query->attribution = 'direct';

                return $query;
            });
            $dates = [];
            $sales = [];
            $startDate = Carbon::parse($start_date);
            $endDate = Carbon::parse($end_date);
            for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
                $values = Cart::select(
                    DB::raw('DATE(created_at) as date'),
                    DB::raw("SUM(case when carts.status = 'completed' then carts.total_amount else 0 end) as amount")
                )
                    ->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
                    ->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
                    ->groupBy(DB::raw('DATE(created_at)'));
                $graphsValues = $values->first();

                $dates[] = $date->format("M d/y");
                if ($graphsValues)
                    $sales[] = $graphsValues->amount;
                else
                    $sales[] = 0;
            }
            $newUser = 0;
            $returnUser = 0;
            $newUsers = [];
            $returningUsers = [];
            //getting here unique rows for patient stats
            $uniqueKeys = array_map(function ($item) {
                return  $item['email'];
            }, $orderCollection->toArray());

            $uniqueRecords = array_intersect_key($orderCollection->toArray(), array_unique($uniqueKeys));
            $uniqueRecords = array_values($uniqueRecords);

            foreach ($orderCollection as $userStats) {
                $userStatus = Cart::where('email', $userStats->email)->count();
                if ($userStatus > 1) {
                    $returnUser++;
                    $returningUsers[] = $userStats;
                } else {
                    $newUser++;
                    $newUsers[] = $userStats;
                }
            };

            $percentageReturning = 0;
            $percentageNewuser = 0;
            if ($returnUser > 0 || $newUser > 0) {
                $percentageReturning = ($returnUser / ($returnUser + $newUser)) * 100;
                $percentageNewuser = ($newUser / ($returnUser + $newUser)) * 100;
            }

            //check here users engagement

            $newUserEngagement = $this->calculateEngagement($newUsers);
            $returningUserEngagement = $this->calculateEngagement($returningUsers);
            return response()->json([
                'totals' => $totalOrdersStats,
                'orders' => $orderData,
                'chart' => [
                    'chart_dates' => $dates,
                    'chart_data' => $sales
                ],
                'patient_stats' =>
                [
                    'returning_users' => [$returnUser, round($percentageReturning, 0) . "%"],
                    'new_users' => [$newUser, round($percentageNewuser, 0) . "%"]
                ]
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function ordersFilters()
    {
        $patient = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))->get();
        return response()->json([
            'patients' => $patient

        ]);
    }
    public function initialPatients()
    {
        $patients = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))
            ->limit(100)
            ->orderBy('patient_name', 'asc')
            ->get();

        return response()->json([
            'patients' => $patients
        ]);
    }

    public function searchPatients(Request $request)
    {
        $searchTerm = $request->input('term');

        $patients = Patient::select('id', DB::raw("CONCAT(first_name,' ',last_name) as patient_name"))
            ->where(DB::raw("CONCAT(first_name,' ',last_name)"), 'LIKE', "%{$searchTerm}%")
            ->limit(500)
            ->orderBy('patient_name', 'asc')
            ->get();

        return response()->json([
            'patients' => $patients
        ]);
    }

    // Function to calculate engagement metrics
    function calculateEngagement($users)
    {
        $totalUsers = count($users);
        $completedOrders = 0;
        $totalAmount = 0;

        foreach ($users as $user) {
            if ($user['status'] === 'delivered') {
                $completedOrders++;
            }
            $totalAmount += floatval($user['total_amount']);
        }

        $orderCompletionRate = $totalUsers > 0 ? ($completedOrders / $totalUsers) * 100 : 0;
        $averageOrderValue = $totalUsers > 0 ? $totalAmount / $totalUsers : 0;

        return [
            'total_users' => $totalUsers,
            'completed_orders' => $completedOrders,
            'order_completion_rate' => $orderCompletionRate,
            'average_order_value' => $averageOrderValue
        ];
    }
    public function ordersReport(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
            $start_date = $request->get('start_date');
            $end_date = $request->get('end_date');
            $status = $request->get('status');
            $patient = $request->get('patient');
            $query = Cart::select(
                'carts.id as order_id',
                'carts.status',
                'carts.email',
                'carts.total_amount',
                'carts.created_at as date',
                DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name")
            )
                ->where('carts.created_at', '>=', $start_date . " 00:00:00")
                ->where('carts.created_at', '<=', $end_date . " 23:59:59");

            // Apply filters
            if ($status != 'all') {
                $query->where('carts.status', $status);
            }

            if ($patient != 'all') {
                $query->where('carts.patient_id', $patient);
            }
            $dates = [];
            $sales = [];
            $startDate = Carbon::parse($start_date);
            $endDate = Carbon::parse($end_date);
            for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
                $values = Cart::select(
                    DB::raw('DATE(created_at) as date'),
                    DB::raw("SUM(carts.total_amount) as amount")
                )
                    ->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
                    ->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
                    ->groupBy(DB::raw('DATE(created_at)'));
                if ($status != 'all') {
                    $values->where('carts.status', $status);
                }

                if ($patient != 'all') {
                    $values->where('carts.patient_id', $patient);
                }
                $graphsValues = $values->first();

                $dates[] = $date->format("M d/y");
                if ($graphsValues)
                    $sales[] = $graphsValues->amount;
                else
                    $sales[] = 0;
            }
            // dd(Constant::getFullSql($query));
            $orderCollection = $query->get();
            $orderData = $orderCollection->map(function ($cart) {
                $patientType = Cart::where('email', $cart->email)->count();

                $itemSold = Item::select(DB::raw("GROUP_CONCAT(plans_v1.title SEPARATOR ', ') as items"))
                    ->where('cart_id', $cart->order_id)
                    ->leftJoin('plans_v1', 'items.plans_id', 'plans_v1.id');
                $itemCount = $itemSold->count();
                $products = $itemSold->first();

                $cart->customer_type = $patientType > 1 ? 'returning' : 'new';
                $cart->products = $products->items ?? null;
                $cart->item_sold = $itemCount ?? null;
                $cart->attribution = 'direct';

                return $cart;
            });
            $totalOrdersStats = Cart::select(
                // DB::raw("sum(case when carts.status = 'delivered' then 1 else 0 end) as total_sales"),
                DB::raw("count(carts.id) as total_sales"),
                DB::raw("sum(carts.total_amount ) as sales_amount"),
                DB::raw("count(items.id) as products_sold")
            )
                ->Join('items', 'items.cart_id', 'carts.id')
                ->where('carts.created_at', '>=', $start_date . " 00:00:00")
                ->where('carts.created_at', '<=', $end_date . " 23:59:59");

            if ($status != 'all') {

                $totalOrdersStats->where('carts.status', $status);
            }

            if ($patient != 'all') {
                $totalOrdersStats->where('carts.patient_id', $patient);
            }
            $totals =  $totalOrdersStats->get();
            return response()->json([
                'orders' => $orderData,
                'totals' => $totals,
                'chart' => [
                    'chart_dates' => $dates,
                    'chart_data' => $sales
                ]
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function productAnalytics(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
            $start_date = $request->get('start_date');
            $end_date = $request->get('end_date');
            $singleProduct = $request->get('single_product');
            $patient = $request->get('patient');
            $query = Item::select(
                DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as total_item_sold"),
                DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
                DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
                'plans_v1.title as product_name',
                'items.plans_id as product_id'
            )
                ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                ->where('items.created_at', '>=', $start_date . " 00:00:00")
                ->where('items.created_at', '<=', $end_date . " 23:59:59")
                ->where('items.status', 'delivered')
                ->groupby('plans_v1.title', 'items.plans_id');
            // Apply filters
            if ($singleProduct != 'all') {
                $query->where('items.plans_id', $singleProduct);
            }

            $dates = [];
            $sales = [];
            $startDate = Carbon::parse($start_date);
            $endDate = Carbon::parse($end_date);
            for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
                $graphsValues = Item::select(
                    DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
                    DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
                )
                    ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                    ->where('items.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
                    ->where('items.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
                    ->where('items.status', 'delivered')
                    ->groupby('plans_v1.title', 'items.plans_id');

                if ($singleProduct != 'all') {
                    $graphsValues->where('items.plans_id', $singleProduct);
                }

                $graphVal = $graphsValues->first();

                $dates[] = $date->format("M d/y");
                if ($graphVal)
                    $sales[] = $graphVal->total_amount;
                else
                    $sales[] = 0;
            }
            $orderData = $query->get();
            $totalOrdersStats = Item::select(
                DB::raw("count(items.id) as total_orders"),
                DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as sales_amount"),
                DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as products_sold")
            )
                ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                ->where('items.created_at', '>=', $start_date . " 00:00:00")
                ->where('items.created_at', '<=', $end_date . " 23:59:59")
                ->where('items.status', 'delivered');

            if ($singleProduct != 'all') {
                $totalOrdersStats->where('items.plans_id', $singleProduct);
            }
            $totals =  $totalOrdersStats->get();
            return response()->json([
                'orders' => $orderData,
                'totals' => $totals,
                'chart' => [
                    'chart_dates' => $dates,
                    'chart_data' => $sales
                ]
            ]);
        } catch (AuthorizationException $e) {
            return  $e->getMessage();
        }
    }
    public function totalSales()
    {
        $start_date = request()->input('start_date');
        $end_date = request()->input('end_date');
        $startDate = Carbon::parse($start_date);
        $endDate = Carbon::parse($end_date);
        $sales = [];
        for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
            $graphsValues = Item::select(
                DB::raw("sum(case when items.status='delivered' then 1 else 0 end) as total_orders"),
                DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as total_amount"),
            )
                ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                ->where('items.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
                ->where('items.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
                ->where('items.status', 'delivered')
                ->groupby('plans_v1.title', 'items.plans_id');

            $graphVal = $graphsValues->first();

            $dates[] = $date->format("M d/y");
            if ($graphVal) {
                $sales[$date->format("Y-m-d")] = ["total_amount" => $graphVal->total_amount, "order_count" => $graphVal->total_orders];
            } else {
                $sales[$date->format("Y-m-d")] = ["total_amount" => 0, "order_count" => 0];
            }
        }
        dd($dates, $sales);
    }
    public function ordersAnalytics(Request $request)
    {
        try {
            $this->authorizeForUser($this->user, 'orders_analytics', new ProfileQuestion);
            $start_date = $request->get('start_date');
            $end_date = $request->get('end_date');
            $singleProduct = $request->get('single_product');
           $query = Cart::select(
                'carts.id as order_id',
                "carts.status as order_status",
                "carts.created_at as order_date",
                DB::raw("GROUP_CONCAT(plans_v1.title SEPARATOR ', ') as items"),
                DB::raw("CONCAT(carts.first_name,' ',carts.last_name) as patient_name"),
                "carts.total_amount",
                DB::raw("sum(case when carts.status='completed' then 1 else 0 end) as item_sold")
                )
                ->leftJoin('items', 'items.cart_id', 'carts.id')
                ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                ->where('carts.created_at', '>=', $start_date . " 00:00:00")
                ->where('carts.created_at', '<=', $end_date . " 23:59:59")
                ->where('carts.status', 'completed')
                ->groupby('carts.id',
                          'carts.status',
                          'carts.created_at',
                          DB::raw("CONCAT(carts.first_name,' ',carts.last_name)"),
                          "carts.total_amount");

            $dates = [];
            $sales = [];
            $singleMonth = [];
            $current_month = null;
            $graphDates = null;
            $startDate = Carbon::parse($start_date);
            $endDate = Carbon::parse($end_date);
            for ($date = $startDate; $date->lte($endDate); $date->addDay())
            {
                $graphsValues = Cart::select(
                    DB::raw('DATE(created_at) as date'),
                    DB::raw("SUM(carts.total_amount) as amount")
                )
                    ->where('carts.created_at', '>=', $date->format("Y-m-d") . " 00:00:00")
                    ->where('carts.created_at', '<=', $date->format("Y-m-d") . " 23:59:59")
                    ->where('carts.status', 'completed')
                    ->groupBy(DB::raw('DATE(created_at)'));
                $graphVal = $graphsValues->first();

                $month = $date->format('F Y');

                if ($month != $current_month)
                {
                    // Month has changed or it's the first iteration, echo the first day of the month
                        $dates[] = $month;
                        $current_month = $month;
                    } else {

                        $dates[] = " ";
                    }

                    $singleMonth[] = $date->format("M d/y");

                    if ($graphVal)
                        $sales[] = $graphVal->amount;
                    else
                        $sales[] = 0;
            }
                // count if user select more then one month
                $dateIterate = $this->monthItrator($start_date, $end_date);
                if ($dateIterate == 1)
                    $graphDates = $singleMonth;
                else
                    $graphDates = $dates;

                $orderData = $query->get();
                $totalOrdersStats = Item::select(
                    DB::raw("count(items.id) as total_orders"),
                    DB::raw("sum(case when items.status='delivered' then (items.quantity*plans_v1.price) else 0 end) as sales_amount"),
                    DB::raw("sum(case when items.status='delivered' then items.quantity else 0 end) as products_sold")
                    )
                    ->leftJoin('plans_v1', 'plans_v1.id', 'items.plans_id')
                    ->where('items.created_at', '>=', $start_date . " 00:00:00")
                    ->where('items.created_at', '<=', $end_date . " 23:59:59")
                    ->where('items.status', 'delivered');

                $totals =  $totalOrdersStats->get();
                return response()->json([
                    'orders' => $orderData,
                    'totals' => $totals,
                    'chart' => [
                        'chart_dates' => $graphDates,
                        'chart_data' => $sales
                    ]
                ]);
            } catch (AuthorizationException $e) {
                return  $e->getMessage();
            }
    }
    public function monthItrator($start_date, $end_date)
    {

        $start = (clone Carbon::parse($start_date))->modify('first day of this month');
        $end = (clone Carbon::parse($end_date))->modify('first day of next month');

        $interval = DateInterval::createFromDateString('1 month');
        $period = new DatePeriod($start, $interval, $end);
        return iterator_count($period);
    }
}
