package click.kamil.springstatemachineexporter.html;

import click.kamil.springstatemachineexporter.exporter.JsonExporter;
import click.kamil.springstatemachineexporter.html.exporter.HtmlExporter;
import click.kamil.springstatemachineexporter.service.ExportService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * Enterprise dedicated and expanded generic REST endpoints must produce HTML explorer link keys end-to-end.
 */
class EnterpriseDedicatedEndpointHtmlTest {

    private static final String PAY_ENDPOINT = "POST /api/machine/order/pay";
    private static final String ORDER_PAY = "POST /api/machine/ORDER/transition/PAY";
    private static final String ORDER_SHIP = "POST /api/machine/ORDER/transition/SHIP";

    @Test
    void htmlShouldExposeLinkKeysForDedicatedAndExpandedOrderEndpoints(@TempDir Path tempDir) throws Exception {
        Path enterprise = findProjectRoot().resolve("state_machines/state_machine_enterprise");
        ExportService exportService = new ExportService(List.of(new HtmlExporter(), new JsonExporter()));
        exportService.runExporter(enterprise, tempDir, List.of("html"), true, List.of(), null, null,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn,
                click.kamil.springstatemachineexporter.exporter.EnumFormat.fn);

        Path htmlFile = findOrderMachineHtml(tempDir);
        String html = Files.readString(htmlFile);

        assertThat(html).contains(PAY_ENDPOINT);
        assertThat(html).contains(ORDER_PAY);
        assertThat(html).contains(ORDER_SHIP);
        assertThat(html).contains("function entryPointsMatch(chainEntryPoint, sidebarEntryPoint)");
        assertThat(html).contains("\"linkResolution\" : \"RESOLVED\"");
        assertThat(html).contains("#link_OrderState_NEW__OrderEvent_PAY");
        assertThat(html).contains("#link_OrderState_PENDING__OrderEvent_SHIP");
        assertThat(html).contains("\"linkKey\" : \"OrderState_NEW__OrderEvent_PAY\"");
        assertThat(html).contains("\"linkKey\" : \"OrderState_PENDING__OrderEvent_SHIP\"");
        assertThat(html).contains("Order fulfillment");
        assertThat(html).contains("function highlightFlow(flow)");
        assertThat(html).contains("\"source\" : \"click.kamil.enterprise.machines.order.OrderState.NEW\"");
        assertThat(html).contains("\"source\" : \"click.kamil.enterprise.machines.order.OrderState.PENDING\"");
        assertThat(html).contains("function highlightEvents(steps)");
        assertThat(html).contains("\"name\" : \"Order fulfillment\"");
        assertThat(html).containsPattern(
                "\"steps\"\\s*:\\s*\\[\\s*\\{[^\\]]*\"linkKey\"\\s*:\\s*\"OrderState_NEW__OrderEvent_PAY\"");
    }

    private static Path findOrderMachineHtml(Path outputDir) throws Exception {
        Path machineDir;
        try (var stream = Files.list(outputDir)) {
            machineDir = stream
                    .filter(Files::isDirectory)
                    .filter(path -> path.getFileName().toString().endsWith("OrderStateMachineConfiguration"))
                    .findFirst()
                    .orElseThrow(() -> new IllegalStateException("Order machine output not found"));
        }
        Path htmlFile = machineDir.resolve(machineDir.getFileName() + ".html");
        assertThat(htmlFile).exists();
        return htmlFile;
    }

    private static Path findProjectRoot() {
        Path current = Path.of(".").toAbsolutePath();
        while (current != null && !Files.exists(current.resolve("settings.gradle"))) {
            current = current.getParent();
        }
        return current;
    }
}
