<?php
declare(strict_types=1);

namespace App\Modules\Printing;

use App\Core\Http\Request;
use App\Core\Http\Response;
use App\Core\Security\Csrf;
use App\Modules\Auth\AuthService;
use App\Modules\Shipments\ShipmentPackageRepository;
use App\Modules\Shipments\ShipmentProviderRegistry;

final class PrintApiController
{
    public function __construct(
        private readonly PrintJobRepository $printJobs,
        private readonly ShipmentPackageRepository $packages,
        private readonly AuthService $auth,
        private readonly string $storagePath,
        private readonly ShipmentProviderRegistry $providers
    ) {
    }

    private function ensureLabel(int $packageId, array $package): string
    {
        $labelPath = (string) ($package['label_path'] ?? '');
        if ($labelPath !== '' && file_exists($this->storagePath . '/' . $labelPath)) {
            return $labelPath;
        }

        $providerCode = strtolower(trim((string) ($package['provider'] ?? 'allegro_wza')));
        $provider = $this->providers->get($providerCode);
        if ($provider === null) {
            return '';
        }

        try {
            $result = $provider->downloadLabel($packageId, $this->storagePath);
            return (string) ($result['label_path'] ?? '');
        } catch (\Throwable $ex) {
            $this->lastLabelError = $ex->getMessage();
            return '';
        }
    }

    private string $lastLabelError = '';

    public function createJob(Request $request): Response
    {
        if (!Csrf::validate((string) $request->input('_token', ''))) {
            return Response::json(['error' => 'Invalid CSRF token'], 403);
        }

        $packageId = (int) $request->input('package_id', 0);
        if ($packageId <= 0) {
            return Response::json(['error' => 'package_id is required'], 400);
        }

        $package = $this->packages->findById($packageId);
        if ($package === null) {
            return Response::json(['error' => 'Package not found'], 404);
        }

        $this->lastLabelError = '';
        $labelPath = $this->ensureLabel($packageId, $package);
        if ($labelPath === '') {
            $msg = 'Etykieta niedostepna';
            if ($this->lastLabelError !== '') {
                $msg .= ': ' . $this->lastLabelError;
            }
            $msg .= '. Kliknij najpierw "Pobierz" aby pobrac etykiete.';
            return Response::json(['error' => $msg], 400);
        }

        $existingPending = $this->printJobs->findPendingByPackageId($packageId);
        if ($existingPending !== null) {
            return Response::json(['error' => 'Zlecenie juz w kolejce'], 409);
        }

        $user = $this->auth->user();
        $orderId = (int) ($package['order_id'] ?? 0);

        $jobId = $this->printJobs->create([
            'order_id' => $orderId,
            'package_id' => $packageId,
            'label_path' => $labelPath,
            'created_by' => (int) ($user['id'] ?? 0),
        ]);

        return Response::json(['id' => $jobId, 'status' => 'pending'], 201);
    }

    public function listPending(Request $request): Response
    {
        $jobs = $this->printJobs->findPending();

        $result = [];
        foreach ($jobs as $job) {
            $result[] = [
                'id' => (int) $job['id'],
                'order_number' => $job['order_number'] ?? '',
                'tracking_number' => $job['tracking_number'] ?? '',
                'created_at' => $job['created_at'] ?? '',
            ];
        }

        return Response::json(['jobs' => $result]);
    }

    public function downloadLabel(Request $request): Response
    {
        $jobId = (int) $request->input('id', 0);
        if ($jobId <= 0) {
            return Response::json(['error' => 'Invalid job ID'], 400);
        }

        $job = $this->printJobs->findById($jobId);
        if ($job === null) {
            return Response::json(['error' => 'Job not found'], 404);
        }

        $labelPath = (string) ($job['label_path'] ?? '');
        $fullPath = $this->storagePath . '/' . $labelPath;

        if (!file_exists($fullPath)) {
            return Response::json(['error' => 'Label file not found'], 404);
        }

        $content = file_get_contents($fullPath);
        if ($content === false) {
            return Response::json(['error' => 'Failed to read label file'], 500);
        }

        $extension = strtolower(pathinfo($labelPath, PATHINFO_EXTENSION));
        $contentType = $extension === 'zpl' ? 'application/octet-stream' : 'application/pdf';
        $filename = 'label_' . $jobId . '.' . ($extension ?: 'pdf');

        return new Response(
            $content,
            200,
            [
                'Content-Type' => $contentType,
                'Content-Disposition' => 'attachment; filename="' . $filename . '"',
            ]
        );
    }

    public function markComplete(Request $request): Response
    {
        $jobId = (int) $request->input('id', 0);
        if ($jobId <= 0) {
            return Response::json(['error' => 'Invalid job ID'], 400);
        }

        $job = $this->printJobs->findById($jobId);
        if ($job === null) {
            return Response::json(['error' => 'Job not found'], 404);
        }

        $this->printJobs->markCompleted($jobId);

        return Response::json(['id' => $jobId, 'status' => 'completed']);
    }

}
