<?php

namespace Tests\Feature\Api\Admin;

use App\Models\Clients\Client;
use App\Models\Monitoring\Log;

/**
 * Catálogos y clientes en la API de administración (PRODSECU-215).
 */
class CatalogosYClientesTest extends ApiDeAdministracionTestCase
{
    public function test_catalogos(): void
    {
        $moodle = $this->tipo('moodle');
        $workplace = $this->tipo('workplace');
        $this->producto('fresk', [$moodle, $workplace]);
        $this->producto('solo-workplace', [$workplace]);
        $this->producto('apagado', [$moodle], ['actived' => false]);
        $this->producto('no-vendible', [$moodle], ['enabled' => false]);

        $token = $this->token(['admin.catalogs.read']);

        $this->api('GET', 'types', [], $token)
            ->assertOk()
            ->assertJsonCount(2, 'data')
            ->assertExactJson(['data' => [
                ['id' => $moodle->id, 'shortname' => 'moodle', 'name' => 'Moodle'],
                ['id' => $workplace->id, 'shortname' => 'workplace', 'name' => 'Workplace'],
            ]]);

        $this->api('GET', 'types?shortname=workplace', [], $token)
            ->assertJsonCount(1, 'data')
            ->assertJsonPath('data.0.id', $workplace->id);

        $this->api('GET', 'envs', [], $token)
            ->assertOk()
            ->assertJsonFragment(['shortname' => 'pro'])
            ->assertJsonFragment(['shortname' => 'local']);

        $this->api('GET', 'envs?shortname=pre', [], $token)->assertJsonCount(1, 'data');

        // Solo activos y habilitados.
        $this->api('GET', 'products', [], $token)
            ->assertOk()
            ->assertJsonCount(2, 'data')
            ->assertJsonPath('data.0.slug', 'fresk')
            ->assertJsonPath('data.0.type_ids', [$moodle->id, $workplace->id]);

        $this->api('GET', 'products?type_id=' . $moodle->id, [], $token)
            ->assertJsonCount(1, 'data')
            ->assertJsonPath('data.0.slug', 'fresk');

        $this->api('GET', 'products?slug=solo-workplace', [], $token)->assertJsonCount(1, 'data');
        $this->assertSame(
            ['id', 'slug', 'name', 'type', 'tech', 'type_ids'],
            array_keys($this->api('GET', 'products', [], $token)->json('data.0'))
        );
    }

    public function test_buscar_clientes_por_nombre_parcial_y_paginado(): void
    {
        $this->cliente('uno', ['name' => 'Universidad de Ejemplo']);
        $this->cliente('dos', ['name' => 'Escuela Ejemplar']);
        $this->cliente('tres', ['name' => 'Otra cosa', 'cif' => 'B12345678', 'crm_id' => 'CRM-1']);

        $token = $this->token(['admin.clients.read']);

        $this->api('GET', 'clients?name=jempl', [], $token)
            ->assertOk()
            ->assertJsonCount(2, 'data')
            ->assertJsonStructure(['data', 'links', 'meta' => ['current_page', 'last_page', 'per_page', 'total']]);

        $this->api('GET', 'clients?cif=B12345678', [], $token)->assertJsonCount(1, 'data')->assertJsonPath('data.0.shortname', 'tres');
        $this->api('GET', 'clients?crm_id=CRM-1', [], $token)->assertJsonCount(1, 'data');
        $this->api('GET', 'clients?shortname=dos', [], $token)->assertJsonCount(1, 'data');

        $this->api('GET', 'clients?per_page=2', [], $token)->assertJsonCount(2, 'data')->assertJsonPath('meta.total', 3);
        $this->api('GET', 'clients?per_page=101', [], $token)->assertStatus(422)->assertJsonStructure(['message', 'errors' => ['per_page']]);
    }

    /** Lo que se puede escribir, se puede leer; lo que no, no sale (el motivo de la baja). */
    public function test_el_cliente_sale_con_todas_sus_propiedades(): void
    {
        $cliente = $this->cliente('completo', [
            'cif' => 'B12345678',
            'razon_social' => 'Completo SL',
            'contacts' => [['name' => 'Ana', 'email' => 'ana@example.com']],
            'observation' => 'Nota interna',
            'description' => 'Descripción interna',
            'crm_id' => 'CRM-9',
        ]);

        $respuesta = $this->api('GET', 'clients/' . $cliente->id, [], $this->token(['admin.clients.read']));

        $respuesta->assertOk()->assertExactJson(['data' => [
            'id' => $cliente->id,
            'name' => 'Cliente completo',
            'shortname' => 'completo',
            'crm_id' => 'CRM-9',
            'cif' => 'B12345678',
            // Alias: en la API, en inglés (`ClienteRequest::ALIAS`).
            'legal_name' => 'Completo SL',
            'relationship_start_date' => null,
            'description' => 'Descripción interna',
            'jira' => null,
            'observation' => 'Nota interna',
            'contacts' => [['name' => 'Ana', 'email' => 'ana@example.com']],
            'actived' => true,
        ]]);
    }

    public function test_crear_cliente(): void
    {
        $respuesta = $this->api('POST', 'clients', [
            'name' => 'Universidad de Ejemplo',
            'shortname' => 'uejemplo',
            'crm_id' => '4567000001234567',
            'cif' => 'Q0000000J',
            // Los de la ficha del panel también se aceptan:
            'legal_name' => 'Universidad de Ejemplo S.L.',
            'relationship_start_date' => '2026-11-01',
            'description' => 'Cliente de prueba',
            'jira' => 'https://tresipunt.atlassian.net/browse/UEJ',
            'observation' => 'Alta automática',
            'contacts' => [
                ['name' => 'Ana', 'email' => 'ana@uejemplo.es', 'phone' => '600000000'],
                ['name' => '', 'email' => '', 'phone' => ''],
            ],
            // Y la baja no:
            'actived' => false,
        ], $this->token(['admin.clients.write'], 'script-altas'));

        $respuesta->assertCreated()
            ->assertJsonPath('data.shortname', 'uejemplo')
            ->assertJsonPath('data.actived', true)
            // Lo que se escribe, se devuelve.
            ->assertJsonPath('data.cif', 'Q0000000J')
            ->assertJsonPath('data.relationship_start_date', '2026-11-01')
            ->assertJsonPath('data.observation', 'Alta automática')
            ->assertJsonCount(1, 'data.contacts');

        $cliente = Client::where('shortname', 'uejemplo')->firstOrFail();
        $this->assertSame('Q0000000J', $cliente->cif);
        $this->assertTrue($cliente->actived);
        $this->assertSame('Universidad de Ejemplo S.L.', $cliente->razon_social);
        $this->assertSame('Alta automática', $cliente->observation);
        $this->assertSame('https://tresipunt.atlassian.net/browse/UEJ', $cliente->jira);
        // La fila vacía se tira, como en el panel.
        $this->assertSame([['name' => 'Ana', 'email' => 'ana@uejemplo.es', 'phone' => '600000000']], $cliente->contacts);

        $log = Log::where('code', '16050')->firstOrFail();
        $this->assertStringContainsString('script-altas', $log->msg);
        $this->assertSame((string) $cliente->id, $log->entity_id);
    }

    public function test_crear_un_cliente_duplicado_es_409_con_el_existente(): void
    {
        $existente = $this->cliente('uejemplo', ['crm_id' => 'CRM-1']);
        $token = $this->token(['admin.clients.write']);

        $this->api('POST', 'clients', ['name' => 'Otro', 'shortname' => 'uejemplo'], $token)
            ->assertStatus(409)
            ->assertJsonPath('data.id', $existente->id)
            ->assertJsonStructure(['message', 'data' => ['id', 'name', 'shortname', 'crm_id', 'actived']]);

        $this->api('POST', 'clients', ['name' => 'Otro', 'shortname' => 'nuevo', 'crm_id' => 'CRM-1'], $token)
            ->assertStatus(409)
            ->assertJsonPath('data.id', $existente->id);

        $this->assertSame(1, Client::count());
    }

    public function test_el_shortname_de_un_cliente_borrado_es_409_sin_datos(): void
    {
        $this->cliente('borrado')->delete();

        $respuesta = $this->api('POST', 'clients', ['name' => 'Otro', 'shortname' => 'borrado'], $this->token(['admin.clients.write']));

        $respuesta->assertStatus(409)->assertJsonMissingPath('data');
        $this->assertStringContainsString('borrado', $respuesta->json('message'));
    }

    public function test_crear_cliente_con_datos_invalidos_es_422(): void
    {
        $this->api('POST', 'clients', ['shortname' => str_repeat('x', 51)], $this->token(['admin.clients.write']))
            ->assertStatus(422)
            ->assertJsonStructure(['message', 'errors' => ['name', 'shortname']]);
    }

    public function test_editar_cliente_no_toca_la_baja(): void
    {
        $cliente = $this->cliente('uejemplo');
        $token = $this->token(['admin.clients.write']);

        $this->api('PATCH', 'clients/' . $cliente->id, ['name' => 'Nuevo nombre', 'actived' => false], $token)
            ->assertOk()
            ->assertJsonPath('data.name', 'Nuevo nombre')
            ->assertJsonPath('data.actived', true);

        $cliente->refresh();
        $this->assertSame('Nuevo nombre', $cliente->name);
        $this->assertSame('uejemplo', $cliente->shortname);
        $this->assertTrue($cliente->actived);
    }

    public function test_editar_cliente_con_un_shortname_ocupado_es_409(): void
    {
        $this->cliente('ocupado');
        $cliente = $this->cliente('uejemplo');

        $this->api('PATCH', 'clients/' . $cliente->id, ['shortname' => 'ocupado'], $this->token(['admin.clients.write']))
            ->assertStatus(409);

        // Su propio shortname no choca consigo mismo.
        $this->api('PATCH', 'clients/' . $cliente->id, ['shortname' => 'uejemplo'], $this->token(['admin.clients.write']))
            ->assertOk();
    }
}
