<?php

namespace App\Http\Controllers\Meet;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\Branch;
use App\Services\Meet\MeetPermissions;
use App\Services\Meet\OrganizationResolver;
use App\Services\Meet\ReportService;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class ReportController extends Controller
{
    use ScopesToAccount;

    public function __construct(
        protected ReportService $reports,
    ) {}

    public function index(Request $request): View
    {
        $this->authorizeAbility($request, 'reports.view');
        $organization = $this->organization($request);

        $branches = Branch::owned($this->ownerRef($request))
            ->where('organization_id', $organization->id)
            ->where('is_active', true)
            ->orderBy('name')
            ->get();

        return view('meet.reports.index', [
            'organization' => $organization,
            'branches' => $branches,
            'reports' => config('meet.report_types'),
        ]);
    }

    public function show(Request $request, string $type): View
    {
        $this->authorizeReport($request, $type);
        $organization = $this->organization($request);
        $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));
        $branchId = $request->input('branch_id') ? (int) $request->input('branch_id') : $branchScope;
        [$from, $to] = $this->dateRange($request);

        $data = $this->reportData($type, $this->ownerRef($request), $organization->id, $from, $to, $branchId);

        $branches = Branch::owned($this->ownerRef($request))
            ->where('organization_id', $organization->id)
            ->orderBy('name')
            ->get();

        return view('meet.reports.show', [
            'type' => $type,
            'label' => config('meet.report_types')[$type] ?? $type,
            'data' => $data,
            'from' => $from->toDateString(),
            'to' => $to->toDateString(),
            'branchId' => $branchId,
            'branches' => $branches,
            'canExport' => app(MeetPermissions::class)->can($this->member($request), 'reports.export'),
        ]);
    }

    public function export(Request $request, string $type): StreamedResponse
    {
        $this->authorizeReport($request, $type);
        abort_unless(app(MeetPermissions::class)->can($this->member($request), 'reports.export'), 403);

        $organization = $this->organization($request);
        $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));
        $branchId = $request->input('branch_id') ? (int) $request->input('branch_id') : $branchScope;
        [$from, $to] = $this->dateRange($request);
        $data = $this->reportData($type, $this->ownerRef($request), $organization->id, $from, $to, $branchId);

        $filename = 'meet-report-'.$type.'-'.now()->format('Y-m-d').'.csv';

        return response()->streamDownload(function () use ($type, $data) {
            echo $this->reports->toCsv($type, $data);
        }, $filename, ['Content-Type' => 'text/csv']);
    }

    /** @return array<string, mixed> */
    protected function reportData(string $type, string $ownerRef, int $organizationId, Carbon $from, Carbon $to, ?int $branchId): array
    {
        return match ($type) {
            'summary' => $this->reports->orgSummary($ownerRef, $organizationId, $from, $to, $branchId),
            'meetings' => $this->reports->meetingsReport($ownerRef, $organizationId, $from, $to, $branchId),
            'users' => $this->reports->usersReport($ownerRef, $organizationId, $from, $to, $branchId),
            'invitations' => $this->reports->invitationsReport($ownerRef, $organizationId, $from, $to, $branchId),
            'branches' => $this->reports->branchRollup($ownerRef, $organizationId, $from, $to),
            default => abort(404),
        };
    }

    protected function authorizeReport(Request $request, string $type): void
    {
        $this->authorizeAbility($request, 'reports.view');
        abort_unless(array_key_exists($type, config('meet.report_types', [])), 404);
    }

    /** @return array{0: Carbon, 1: Carbon} */
    protected function dateRange(Request $request): array
    {
        $from = Carbon::parse($request->input('from', now()->subDays(30)->toDateString()))->startOfDay();
        $to = Carbon::parse($request->input('to', now()->toDateString()))->endOfDay();

        return [$from, $to];
    }
}
