<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Tests\Integration;

use OCA\Mitgliederverwaltung\Controller\FileController;
use OCA\Mitgliederverwaltung\Service\FileLinkService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\IRequest;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

/**
 * Integration-level tests for FileController API endpoints.
 */
class FileControllerTest extends TestCase {

    private FileController $controller;
    private FileLinkService&MockObject $fileLinkService;
    private IRequest&MockObject $request;
    private LoggerInterface&MockObject $logger;

    protected function setUp(): void {
        parent::setUp();

        $this->fileLinkService = $this->createMock(FileLinkService::class);
        $this->request = $this->createMock(IRequest::class);
        $this->logger = $this->createMock(LoggerInterface::class);

        $this->controller = new FileController(
            'mitgliederverwaltung',
            $this->request,
            $this->fileLinkService,
            $this->logger
        );
    }

    // ── GET /api/v1/files/settings ─────────────────────────────────

    public function testGetSettingsReturns200(): void {
        $settings = ['basePath' => '/Members', 'autoCreate' => true];
        $this->fileLinkService->method('getSettings')->willReturn($settings);

        $response = $this->controller->getSettings();

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
        $this->assertSame($settings, $response->getData());
    }

    public function testGetSettingsReturns500OnException(): void {
        $this->fileLinkService->method('getSettings')
            ->willThrowException(new \RuntimeException('fail'));

        $response = $this->controller->getSettings();

        $this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
    }

    // ── PUT /api/v1/files/settings ─────────────────────────────────

    public function testUpdateSettingsReturns200(): void {
        $settings = ['basePath' => '/Updated', 'autoCreate' => false];
        $this->fileLinkService->method('getSettings')->willReturn($settings);

        $response = $this->controller->updateSettings();

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
    }

    public function testUpdateSettingsReturns500OnException(): void {
        $this->fileLinkService->method('getSettings')
            ->willThrowException(new \RuntimeException('fail'));

        $response = $this->controller->updateSettings();

        $this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
    }

    // ── GET /api/v1/members/{memberId}/files ───────────────────────

    public function testMemberFilesReturns200(): void {
        $result = ['files' => [['name' => 'doc.pdf']]];
        $this->fileLinkService->method('getMemberFilesById')
            ->with(1)
            ->willReturn($result);

        $response = $this->controller->memberFiles(1);

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
    }

    public function testMemberFilesReturns404ForMissingMember(): void {
        $this->fileLinkService->method('getMemberFilesById')
            ->willThrowException(new DoesNotExistException(''));

        $response = $this->controller->memberFiles(9999);

        $this->assertSame(Http::STATUS_NOT_FOUND, $response->getStatus());
    }

    public function testMemberFilesReturns500OnException(): void {
        $this->fileLinkService->method('getMemberFilesById')
            ->willThrowException(new \RuntimeException('fail'));

        $response = $this->controller->memberFiles(1);

        $this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
    }

    // ── POST /api/v1/members/{memberId}/files/ensure-folder ────────

    public function testEnsureFolderReturns200WhenExists(): void {
        $this->fileLinkService->method('ensureMemberFolderById')
            ->with(1)
            ->willReturn(['exists' => true, 'path' => '/Members/Max']);

        $response = $this->controller->ensureFolder(1);

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
        $this->assertSame('ok', $response->getData()['status']);
        $this->assertSame('/Members/Max', $response->getData()['path']);
    }

    public function testEnsureFolderReturns400WhenNotCreated(): void {
        $this->fileLinkService->method('ensureMemberFolderById')
            ->willReturn(['exists' => false, 'path' => '']);

        $response = $this->controller->ensureFolder(1);

        $this->assertSame(Http::STATUS_BAD_REQUEST, $response->getStatus());
    }

    public function testEnsureFolderReturns404ForMissingMember(): void {
        $this->fileLinkService->method('ensureMemberFolderById')
            ->willThrowException(new DoesNotExistException(''));

        $response = $this->controller->ensureFolder(9999);

        $this->assertSame(Http::STATUS_NOT_FOUND, $response->getStatus());
    }

    public function testEnsureFolderReturns500OnException(): void {
        $this->fileLinkService->method('ensureMemberFolderById')
            ->willThrowException(new \RuntimeException('fail'));

        $response = $this->controller->ensureFolder(1);

        $this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
    }

    // ── GET /api/v1/lager/{lagerId}/files/browse ───────────────────

    public function testLagerFilesReturns200WithFiles(): void {
        $this->fileLinkService->method('getLagerFilesById')
            ->with(1)
            ->willReturn([
                'exists' => true,
                'path' => '/Lager/2026',
                'files' => [['name' => 'plan.pdf']],
            ]);

        $response = $this->controller->lagerFiles(1);

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
        $data = $response->getData();
        $this->assertTrue($data['exists']);
        $this->assertSame('/Lager/2026', $data['path']);
    }

    public function testLagerFilesReturns200WithExistsFalseWhenFolderMissing(): void {
        $this->fileLinkService->method('getLagerFilesById')
            ->with(1)
            ->willReturn([
                'exists' => false,
                'path' => '/Lager/nonexistent',
                'files' => [],
            ]);

        $response = $this->controller->lagerFiles(1);

        $this->assertSame(Http::STATUS_OK, $response->getStatus());
        $this->assertFalse($response->getData()['exists']);
    }

    public function testLagerFilesReturns404ForMissingLager(): void {
        $this->fileLinkService->method('getLagerFilesById')
            ->willThrowException(new \OCP\AppFramework\Db\DoesNotExistException(''));

        $response = $this->controller->lagerFiles(999);

        $this->assertSame(Http::STATUS_NOT_FOUND, $response->getStatus());
    }

    public function testLagerFilesReturns500OnException(): void {
        $this->fileLinkService->method('getLagerFilesById')
            ->willThrowException(new \RuntimeException('fail'));

        $response = $this->controller->lagerFiles(1);

        $this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
    }
}
