<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Helpers\Response;
use App\Services\MaterialService;

class MaterialController extends BaseController
{
    private MaterialService $materialService;

    public function __construct($request)
    {
        parent::__construct($request);
        $this->materialService = new MaterialService();
    }

    public function index(): void
    {
        try {
            $filters = [
                'search' => $this->request->query('search'),
                'type' => $this->request->query('type'),
                'category_id' => $this->request->query('category_id'),
                'status' => $this->request->query('status'),
            ];
            $page = (int) ($this->request->query('page', 1));
            $perPage = (int) ($this->request->query('per_page', 20));

            $result = $this->materialService->getMaterials($filters, $page, $perPage);

            Response::paginated($result['items'], $result['total'], $result['page'], $result['per_page'], 'Materiales consultados correctamente');
        } catch (\Throwable $e) {
            Response::error($e->getMessage(), 500);
        }
    }

    public function show(): void
    {
        $id = (int) $this->getRouteParam('id');
        try {
            $material = $this->materialService->getMaterial($id);
            Response::success($material, 'Material consultado correctamente');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    public function store(): void
    {
        $data = $this->request->body();
        $file = $this->request->uploadedFile('file');

        $validation = $this->validate($data, function ($v) {
            $v->required('title', 'Título');
            $v->required('type', 'Tipo')
              ->inValues('type', ['pdf', 'video', 'image', 'document'], 'Tipo');
        });

        if ($validation->fails()) {
            Response::error($validation->firstError(), 422);
        }

        try {
            $material = $this->materialService->uploadMaterial($data, $file ?? [], $this->getAuthUserId());
            Response::created($material, 'Material creado correctamente');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        } catch (\Throwable $e) {
            Response::error($e->getMessage(), 500);
        }
    }

    public function update(): void
    {
        $id = (int) $this->getRouteParam('id');
        $data = $this->request->body();

        try {
            $material = $this->materialService->updateMaterial($id, $data);
            Response::success($material, 'Material actualizado correctamente');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    public function updateWithFile(): void
    {
        $id = (int) $this->getRouteParam('id');
        $data = $this->request->body();
        $file = $this->request->uploadedFile('file');

        try {
            $material = $this->materialService->updateMaterialWithFile($id, $data, $file ?? []);
            Response::success($material, 'Material actualizado correctamente');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    public function destroy(): void
    {
        $id = (int) $this->getRouteParam('id');

        try {
            $this->materialService->deleteMaterial($id);
            Response::success(null, 'Material eliminado correctamente');
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    public function download(): void
    {
        $id = (int) $this->getRouteParam('id');

        try {
            $material = $this->materialService->downloadMaterial($id);

            $contentTypes = [
                'pdf' => 'application/pdf',
                'video' => 'video/mp4',
                'image' => 'image/jpeg',
                'document' => 'application/octet-stream',
            ];
            $contentType = $contentTypes[$material['type']] ?? 'application/octet-stream';
            $fileName = $this->getDownloadFilename($material);

            Response::download($material['file_path'], $fileName, $contentType);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    public function shared(): void
    {
        $token = $this->getRouteParam('token');

        try {
            $material = $this->materialService->getPublicMaterial($token);

            $contentTypes = [
                'pdf' => 'application/pdf',
                'video' => 'video/mp4',
                'image' => 'image/jpeg',
                'document' => 'application/octet-stream',
            ];
            $contentType = $contentTypes[$material['type']] ?? 'application/octet-stream';
            $fileName = $this->getDownloadFilename($material);

            Response::download($material['file_path'], $fileName, $contentType);
        } catch (\RuntimeException $e) {
            Response::error($e->getMessage(), $e->getCode() ?: 400);
        }
    }

    private function getDownloadFilename(array $material): string
    {
        $ext = pathinfo($material['file_path'] ?? '', PATHINFO_EXTENSION);
        if (!$ext) {
            $extMap = ['pdf'=>'pdf', 'video'=>'mp4', 'image'=>'jpg', 'document'=>'bin'];
            $ext = $extMap[$material['type']] ?? 'bin';
        }
        $name = preg_replace('/[^a-zA-Z0-9_-]/u', '_', $material['title'] ?? 'archivo');
        $name = mb_substr($name, 0, 60);
        return $name . '.' . $ext;
    }
}
