package com.developx.szpitale.load;

import com.developx.szpitale.model.*;
import com.developx.szpitale.model.enums.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.*;
import org.testcontainers.containers.Neo4jContainer;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class GraphLoaderIT {

    private static Neo4jContainer<?> neo4j;
    private static Driver driver;

    @BeforeAll
    static void setup() {
        neo4j = new Neo4jContainer<>("neo4j:5")
            .withEnv("NEO4J_AUTH", "neo4j/password");
        neo4j.start();
        driver = GraphDatabase.driver(
            neo4j.getBoltUrl(),
            AuthTokens.basic("neo4j", "password")
        );
    }

    @AfterAll
    static void teardown() {
        if (driver != null) driver.close();
        if (neo4j != null) neo4j.close();
    }

    @Test
    void load_twice_isIdempotent() {
        GraphSchema schema = new GraphSchema(driver);
        schema.createConstraints();

        Hospital hospital = new Hospital(
            "hosp:test:test-szpital",
            "Test Szpital",
            "TS",
            "TestCity",
            "test",
            LegalForm.SPZOZ,
            "Tester",
            SupervisoryBodyType.RADA_SPOLECZNA,
            null, null, "https://test.pl",
            List.of("https://test.pl")
        );

        Person person = new Person(
            "person:test-osoba",
            "Test Osoba",
            "Dyrektor",
            List.of(),
            List.of("https://test.pl")
        );

        CanonicalDataset dataset = new CanonicalDataset(
            "1.0", "test",
            java.time.LocalDateTime.now(),
            List.of(hospital),
            List.of(person),
            List.of(),
            List.of(new Role(
                "hosp:test:test-szpital",
                "person:test-osoba",
                RoleType.DYREKTOR,
                "Dyrektor",
                OrganType.DYREKCJA,
                RoleStatus.AKTUALNY,
                null, null, null,
                List.of("https://test.pl")
            )),
            List.of()
        );

        GraphLoader loader = new GraphLoader(driver);
        loader.load(List.of(dataset));
        loader.load(List.of(dataset));

        try (Session session = driver.session()) {
            String cypher = "MATCH (h:Hospital {id: \"hosp:test:test-szpital\"}) RETURN count(h) AS cnt";
            long hospitalCount = session.run(cypher).single().get("cnt").asInt();
            assertEquals(1, hospitalCount, "Should have exactly 1 hospital node after double load");

            cypher = "MATCH (p:Person {id: \"person:test-osoba\"}) RETURN count(p) AS cnt";
            long personCount = session.run(cypher).single().get("cnt").asInt();
            assertEquals(1, personCount, "Should have exactly 1 person node after double load");
        }
    }

    @Test
    void schema_constraints_created() {
        GraphSchema schema = new GraphSchema(driver);
        schema.createConstraints();

        try (Session session = driver.session()) {
            session.run("CREATE (h:Hospital {id: \"cons-test\"})");
            
            try {
                session.run("CREATE (h:Hospital {id: \"cons-test\"})");
                fail("Should have thrown due to unique constraint");
            } catch (Exception e) {
                assertTrue(e.getMessage().contains("constraint") || 
                           e.getMessage().contains("already exists") ||
                           e.getMessage().contains("UniqueProperties"));
            }
        }
    }
}
