<?php

namespace App\Http\Controllers\Admin;

use App\Constants\Status;
use App\Http\Controllers\Controller;
use App\Lib\ResponseTime;
use App\Models\Admin;
use App\Models\Department;
use App\Models\Priority;
use App\Models\SupportTicket;
use Carbon\Carbon;
use Illuminate\Http\Request;

class AnalyticsController extends Controller
{
    public function ticketSevenDays()
    {
        $pageTitle   = '7 Days Analytics';
        $departments = Department::get();
        $agents      = Admin::get();

        return view('admin.analytics.seven_days_ticket', compact('pageTitle', 'departments', 'agents'));
    }

    public function ticketDataByDepartment(Request $request)
    {
        $supportTickets = SupportTicket::where('created_at', '>=', now()->subDays(6)->startOfDay());

        if ($request->department) {
            $supportTickets->where('department_id', $request->department)->selectRaw("DATE_FORMAT(created_at, '%d %M') as date, COUNT(*) as total")
                ->groupBy('date')
                ->orderByRaw("STR_TO_DATE(date, '%d %M')")
                ->get();

            $data = $supportTickets->pluck('total', 'date');
        } else {
            $supportTickets->with('department')
                ->selectRaw('department_id, COUNT(*) as total')
                ->groupBy('department_id')
                ->get();

            $data = $supportTickets->get()->mapWithKeys(function ($ticket) {
                return [$ticket->department->name => $ticket->total];
            });
        }

        return [
            'keys'   => $data->keys()->all(),
            'values' => $data->values()->all(),
        ];
    }

    public function ticketDataByChannel()
    {
        $supportTickets = SupportTicket::where('created_at', '>=', now()->subDays(6)->startOfDay())->selectRaw("COUNT(*) as total, created_via")->groupBy('created_via')->get();

        $admin = $supportTickets->where('created_via', Status::CREATED_VIA_ADMIN)->first();
        $web   = $supportTickets->where('created_via', Status::CREATED_VIA_WEB)->first();
        $email = $supportTickets->where('created_via', Status::CREATED_VIA_EMAIL)->first();

        $result['admin'] = $admin ? $admin->total : 0;
        $result['web']   = $web ? $web->total : 0;
        $result['email'] = $email ? $email->total : 0;
        $result['total'] = $result['admin'] + $result['web'] + $result['email'];

        $result['admin_percent'] = $result['admin'] > 0 ? getAmount($result['admin'] / $result['total'] * 100) : 0;
        $result['web_percent']   = $result['web'] > 0 ? getAmount($result['web'] / $result['total'] * 100) : 0;
        $result['email_percent'] = $result['email'] > 0 ? getAmount($result['email'] / $result['total'] * 100) : 0;

        return $result;
    }

    public function ticketDataByRating(Request $request)
    {
        $supportTickets = SupportTicket::whereNotNull('rated_at')
            ->where('rated_at', '>=', now()->subDays(6)->startOfDay())
            ->selectRaw("DATE_FORMAT(rated_at, '%d %M') as date, customer_happiness, COUNT(*) as total")
            ->groupBy('date', 'customer_happiness')
            ->orderByRaw("STR_TO_DATE(date, '%d %M')")
            ->get();

        $dates  = $supportTickets->pluck('date')->unique()->values();
        $result = [
            'keys'  => $dates->all(),
            'great' => [],
            'okay'  => [],
            'bad'   => [],
        ];

        foreach ($dates as $date) {
            $great = $supportTickets->where('date', $date)->where('customer_happiness', 'great')->first();
            $okay  = $supportTickets->where('date', $date)->where('customer_happiness', 'okay')->first();
            $bad   = $supportTickets->where('date', $date)->where('customer_happiness', 'bad')->first();

            if ($request->rating == 'great') {
                $result['great'][] = $great ? $great->total : 0;
            } elseif ($request->rating == 'okay') {
                $result['okay'][] = $okay ? $okay->total : 0;
            } elseif ($request->rating == 'bad') {
                $result['bad'][] = $bad ? $bad->total : 0;
            } else {
                $result['great'][] = $great ? $great->total : 0;
                $result['okay'][]  = $okay ? $okay->total : 0;
                $result['bad'][]   = $bad ? $bad->total : 0;
            }
        }

        if (!$request->rating) {
            $greatCount   = array_sum($result['great']);
            $okayCount    = array_sum($result['okay']);
            $badCount     = array_sum($result['bad']);
            $total        = $greatCount + $okayCount + $badCount;
            $greatPercent = $total ? $greatCount / $total * 100 : 0;
            $okayPercent  = $total ? $okayCount / $total * 100 : 0;
            $badPercent   = $total ? $badCount / $total * 100 : 0;

            $result['statistics'] = [
                'great'         => $greatCount,
                'okay'          => $okayCount,
                'bad'           => $badCount,
                'great_percent' => showAmount($greatPercent),
                'okay_percent'  => showAmount($okayPercent),
                'bad_percent'   => showAmount($badPercent),
            ];
        }

        return $result;
    }

    public function ticket()
    {
        $pageTitle   = 'Ticket Analytics';
        $departments = Department::get();
        $priorities  = Priority::get();

        return view('admin.analytics.ticket', compact('pageTitle', 'departments', 'priorities'));
    }

    public function ticketData(Request $request)
    {
        $supportTickets = SupportTicket::query();

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
        }

        if ($request->department_id) {
            $supportTickets->where('department_id', $request->department_id);
        }

        if ($request->priority_id) {
            $supportTickets->where('priority_id', $request->priority_id);
        }

        $supportTickets->selectRaw("DATE_FORMAT(created_at, '%d %M') as date, COUNT(*) as total")
            ->groupBy('date')
            ->orderByRaw("STR_TO_DATE(date, '%d %M')")
            ->get();

        $data = $supportTickets->pluck('total', 'date');

        return [
            'keys'   => $data->keys()->all(),
            'values' => $data->values()->all(),
        ];
    }

    public function ticketSourceData(Request $request)
    {
        $supportTickets = SupportTicket::query();

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
        }

        $supportTickets = $supportTickets->selectRaw("DATE_FORMAT(created_at, '%d %M') as date, COUNT(*) as total, created_via")
            ->groupBy('date', 'created_via')
            ->get();

        $dates  = $supportTickets->pluck('date')->unique()->values();
        $result = [
            'keys'  => $dates->all(),
            'admin' => [],
            'web'   => [],
            'email' => [],
        ];

        foreach ($dates as $date) {
            $admin = $supportTickets->where('date', $date)->where('created_via', Status::CREATED_VIA_ADMIN)->first();
            $web   = $supportTickets->where('date', $date)->where('created_via', Status::CREATED_VIA_WEB)->first();
            $email = $supportTickets->where('date', $date)->where('created_via', Status::CREATED_VIA_EMAIL)->first();

            $result['admin'][] = $admin ? $admin->total : 0;
            $result['web'][]   = $web ? $web->total : 0;
            $result['email'][] = $email ? $email->total : 0;
        }

        $adminCount   = array_sum($result['admin']);
        $webCount     = array_sum($result['web']);
        $emailCount   = array_sum($result['email']);
        $total        = $adminCount + $webCount + $emailCount;
        $adminPercent = $total ? $adminCount / $total * 100 : 0;
        $webPercent   = $total ? $webCount / $total * 100 : 0;
        $emailPercent = $total ? $emailCount / $total * 100 : 0;

        $result['statistics'] = [
            'admin'         => $adminCount,
            'web'           => $webCount,
            'email'         => $emailCount,
            'admin_percent' => showAmount($adminPercent),
            'web_percent'   => showAmount($webPercent),
            'email_percent' => showAmount($emailPercent),
        ];

        return $result;
    }

    public function agentFirstResponseTime(Request $request)
    {
        $supportTickets = SupportTicket::where('created_at', '>=', now()->subDays(6)->startOfDay());

        if ($request->agent) {
            $supportTickets = (clone $supportTickets)->whereHas('replies', fn($reply) => $reply->where('admin_id', $request->agent));
        } else {
            $supportTickets = (clone $supportTickets)->whereHas('replies', fn($reply) => $reply->where('admin_id', '!=', 0));
        }

        $supportTickets = $supportTickets->with('replies')->get();

        $result = ResponseTime::getFirstResponseTime($supportTickets, adminId: $request->agent);

        return $result;
    }

    public function responseTime()
    {
        $pageTitle   = 'First Response Time';
        $agents      = Admin::get();
        $departments = Department::get();
        $priorities  = Priority::get();

        return view('admin.analytics.first_response_time', compact('pageTitle', 'agents', 'departments', 'priorities'));
    }

    public function agentResponseTime(Request $request)
    {
        $supportTickets = SupportTicket::query();

        if ($request->agent) {
            $supportTickets->whereHas('replies', fn($reply) => $reply->where('admin_id', $request->agent));
        } else {
            $supportTickets->whereHas('replies', fn($reply) => $reply->where('admin_id', '!=', 0));
        }

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at',
                '<=', $endDate->toDateString());
        }

        $supportTickets      = $supportTickets->get();
        $result              = ResponseTime::getFirstResponseTime($supportTickets, adminId: $request->agent);
        $result['agent_avg'] = sprintf('%dh %dmin %ds', $h = floor($result['avg_first_response'] / 3600), $m = floor(($result['avg_first_response'] % 3600) / 60), $s = round($result['avg_first_response'] % 60));
        return $result;
    }

    public function agentBarResponseTime(Request $request)
    {
        $agents = Admin::with(['supportTickets' => function ($ticket) use ($request) {
            $date = $request->date;
            if ($date) {
                list($startDate, $endDate) = getDateFromRange($date);
                $ticket->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at',
                    '<=', $endDate->toDateString());
            }

            $priority = $request->priority;

            if($priority){
                $ticket->where('priority_id', $priority);
            }

        }])->get();

        $data = [];

        foreach ($agents as $agent) {
            if($agent->supportTickets->count()){
                $avgResTime         = ResponseTime::getAvgResponseTime($agent->supportTickets);
                $data[$agent->name] = $avgResTime;
            }
        }

        return [
            'keys'   => array_keys($data),
            'values' => array_values($data),
        ];

    }

    public function userResponseTime(Request $request)
    {
        $supportTickets = SupportTicket::query();

        if ($request->department) {
            $supportTickets->where('department_id', $request->department);
        }

        if ($request->priority) {
            $supportTickets->where('priority_id', $request->priority);
        }

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at',
                '<=', $endDate->toDateString());
        }

        $supportTickets         = $supportTickets->whereHas('replies', fn($reply) => $reply->where('admin_id', 0))->with('replies')->get();
        $result                 = ResponseTime::getFirstResponseTime($supportTickets, false);
        $result['customer_avg'] = sprintf('%dh %dmin %ds', $h = floor($result['avg_first_response'] / 3600), $m = floor(($result['avg_first_response'] % 3600) / 60), $s = round($result['avg_first_response'] % 60));

        return $result;
    }

    public function resolutionTime()
    {
        $pageTitle   = 'Resolution Time';
        $departments = Department::get();
        $priorities  = Priority::get();
        $agents      = Admin::get();

        return view('admin.analytics.resolution_time', compact('pageTitle', 'departments', 'priorities', 'agents'));
    }

    public function resolutionTimeData(Request $request)
    {
        $supportTickets = SupportTicket::query();

        if ($request->department) {
            $supportTickets->where('department_id', $request->department);
        }

        if ($request->priority) {
            $supportTickets->where('priority_id', $request->priority);
        }

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereHas('ticketLogs', function ($ticketLog) use ($startDate, $endDate) {
                $ticketLog->where('remark', 'closed')->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
            });
        }

        $supportTickets = $supportTickets->get();

        $resolutionType = $request->resolution_type == 'creation' ? true : false;
        $resolutionTime = ResponseTime::getResolutionTime($supportTickets, $resolutionType, dateWise: true);

        return [
            'keys'   => $resolutionTime['keys'],
            'values' => $resolutionTime['values'],
            'avg'    => formatSecondsToHoursMinutes($resolutionTime['avg_resolution']),
        ];
    }

    public function channelWiseResponseTime()
    {
        $supportTickets = SupportTicket::query();

        $createdByAdmin = (clone $supportTickets)->where('created_via', Status::CREATED_VIA_ADMIN)->get();
        $createdByWeb   = (clone $supportTickets)->where('created_via', Status::CREATED_VIA_WEB)->get();
        $createdByEmail = (clone $supportTickets)->where('created_via', Status::CREATED_VIA_EMAIL)->get();

        $createdByAdminTime = ResponseTime::getAvgResponseTime($createdByAdmin);
        $createdByWebTime   = ResponseTime::getAvgResponseTime($createdByWeb);
        $createdByEmailTime = ResponseTime::getAvgResponseTime($createdByEmail);

        $result['admin'] = formatSecondsToHoursMinutes($createdByAdminTime);
        $result['web']   = formatSecondsToHoursMinutes($createdByWebTime);
        $result['email'] = formatSecondsToHoursMinutes($createdByEmailTime);

        $totalTime = $createdByAdminTime + $createdByWebTime + $createdByEmailTime;

        $result['admin_percent'] = $createdByAdminTime > 0 ? getAmount($createdByAdminTime / $totalTime * 100, 2) : 0;
        $result['web_percent']   = $createdByWebTime > 0 ? getAmount($createdByWebTime / $totalTime * 100, 2) : 0;
        $result['email_percent'] = $createdByEmailTime > 0 ? getAmount($createdByEmailTime / $totalTime * 100, 2) : 0;

        return $result;
    }

    public function satisfaction()
    {
        $pageTitle = 'Customer Satisfaction';
        $agents    = Admin::get();

        return view('admin.analytics.satisfaction', compact('pageTitle', 'agents'));
    }

    public function satisfactionData(Request $request, $type = 'agent')
    {
        $column = $type == 'customer' ? 'customer_happiness' : 'admin_happiness';

        $supportTickets = SupportTicket::where($column, '!=', null);

        if ($request->admin) {
            $supportTickets->where('assign_staff_id', $request->admin);
        }

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
        }

        $supportTickets = $supportTickets->selectRaw("DATE_FORMAT(created_at, '%d %M') as date, $column, COUNT(*) as total")->groupBy('date', $column)->get();

        $dates = $supportTickets->pluck('date')->unique()->values();

        $dates = $dates->sortBy(function ($date) {
            return Carbon::createFromFormat('d F', $date);
        })->values();

        $result = [
            'keys'  => $dates->all(),
            'great' => [],
            'okay'  => [],
            'bad'   => [],
        ];

        foreach ($dates as $date) {
            $great = $supportTickets->where('date', $date)->where($column, 'great')->first();
            $okay  = $supportTickets->where('date', $date)->where($column, 'okay')->first();
            $bad   = $supportTickets->where('date', $date)->where($column, 'bad')->first();

            $result['great'][] = $great ? $great->total : 0;
            $result['okay'][]  = $okay ? $okay->total : 0;
            $result['bad'][]   = $bad ? $bad->total : 0;
        }

        $greatCount   = array_sum($result['great']);
        $okayCount    = array_sum($result['okay']);
        $badCount     = array_sum($result['bad']);
        $total        = $greatCount + $okayCount + $badCount;
        $greatPercent = $total ? $greatCount / $total * 100 : 0;
        $okayPercent  = $total ? $okayCount / $total * 100 : 0;
        $badPercent   = $total ? $badCount / $total * 100 : 0;

        $result['statistics'] = [
            'great'         => $greatCount,
            'okay'          => $okayCount,
            'bad'           => $badCount,
            'great_percent' => showAmount($greatPercent),
            'okay_percent'  => showAmount($okayPercent),
            'bad_percent'   => showAmount($badPercent),
        ];

        return $result;
    }

    public function openedAndClosed()
    {
        $pageTitle   = 'Opened and Closed';
        $departments = Department::get();
        $priorities  = Priority::get();

        return view('admin.analytics.opened_and_closed', compact('pageTitle', 'departments', 'priorities'));
    }

    public function openedAndClosedData(Request $request)
    {
        $supportTickets = SupportTicket::query();

        if ($request->department) {
            $supportTickets->where('department_id', $request->department);
        }

        if ($request->priority) {
            $supportTickets->where('priority_id', $request->priority);
        }

        $closedLogs = (clone $supportTickets)->closed()
            ->join('ticket_logs', 'support_tickets.id', '=', 'ticket_logs.support_ticket_id')
            ->where('ticket_logs.remark', 'closed');

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $closedLogs->whereDate('ticket_logs.created_at', '>=', $startDate->toDateString())->whereDate('ticket_logs.created_at', '<=', $endDate->toDateString());
        }

        $closedLogs = $closedLogs->selectRaw("DATE_FORMAT(ticket_logs.created_at, '%d %M') as date, COUNT(*) as total")
            ->groupBy('date')
            ->get();

        $closedDates = $closedLogs->pluck('date')->unique()->values();

        $openedLogs = (clone $supportTickets);

        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $openedLogs->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
        }

        $openedLogs = $openedLogs->selectRaw("DATE_FORMAT(created_at, '%d %M') as date, COUNT(*) as total")->groupBy('date')->get();
        $openDates  = $openedLogs->pluck('date')->unique()->values();

        $dates = $closedDates->merge($openDates)->unique();

        $dates = $dates->sortBy(function ($date) {
            return Carbon::createFromFormat('d F', $date);
        })->values();

        $result['keys'] = $dates;

        foreach ($dates as $date) {
            $closedLog = $closedLogs->where('date', $date)->first();
            $openedLog = $openedLogs->where('date', $date)->first();

            $result['closed'][] = $closedLog ? $closedLog->total : 0;
            $result['opened'][] = $openedLog ? $openedLog->total : 0;
        }

        $result['total_opened'] = array_sum($result['opened'] ?? []);
        $result['total_closed'] = array_sum($result['closed'] ?? []);
        $result['total']        = $result['total_opened'] + $result['total_closed'];

        $result['opened_percent'] = $result['total_opened'] > 0 ? getAmount($result['total_opened'] / $result['total'] * 100, 2) : 0;
        $result['closed_percent'] = $result['total_closed'] > 0 ? getAmount($result['total_closed'] / $result['total'] * 100, 2) : 0;

        return $result;
    }

    public function statusData(Request $request)
    {
        $supportTickets = SupportTicket::query();
        
        $date = $request->date;
        if ($date) {
            list($startDate, $endDate) = getDateFromRange($date);
            $supportTickets->whereDate('created_at', '>=', $startDate->toDateString())->whereDate('created_at', '<=', $endDate->toDateString());
        }

        if ($request->department) {
            $supportTickets->where('department_id', $request->department);
        }

        if ($request->priority) {
            $supportTickets->where('priority_id', $request->priority);
        }

        $supportTickets = $supportTickets->with('ticketStatus')->selectRaw("ticket_status_id, COUNT(*) as total")
            ->groupBy('ticket_status_id')
            ->get();

        $data = $supportTickets->mapWithKeys(function ($ticket) {
            return [$ticket->ticketStatus->name => $ticket->total];
        });

        $colors = $supportTickets->mapWithKeys(function ($ticket) {
            return [$ticket->ticketStatus->name => '#' . $ticket->ticketStatus->color];
        })->values()->all();

        $result['colors'] = $colors;

        $result['keys']   = $data->keys()->all();
        $result['values'] = $data->values()->all();
        $result['data']   = $data;
        $result['total']  = array_sum($result['values']);
        
        return $result;
    }

}
