package dev.lions.unionflow.server.resource;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import dev.lions.unionflow.server.api.dto.backup.request.CreateBackupRequest;
import dev.lions.unionflow.server.api.dto.backup.request.RestoreBackupRequest;
import dev.lions.unionflow.server.api.dto.backup.request.UpdateBackupConfigRequest;
import dev.lions.unionflow.server.api.dto.backup.response.BackupConfigResponse;
import dev.lions.unionflow.server.api.dto.backup.response.BackupResponse;
import dev.lions.unionflow.server.service.BackupService;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Tests d'intégration REST pour BackupResource.
 * Utilise @InjectMock BackupService pour isoler la ressource de la logique métier.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-21
 */
@QuarkusTest
class BackupResourceTest {

    private static final String BASE_PATH = "/api/backups";

    @InjectMock
    BackupService backupService;

    private BackupResponse sampleBackup;
    private BackupConfigResponse sampleConfig;

    @BeforeEach
    void setUp() {
        sampleBackup = BackupResponse.builder()
                .id(UUID.fromString("00000000-0000-0000-0000-000000000001"))
                .name("Sauvegarde test")
                .description("Description test")
                .type("MANUAL")
                .sizeBytes(1_000_000L)
                .sizeFormatted("1 MB")
                .status("COMPLETED")
                .createdAt(LocalDateTime.now().minusHours(1))
                .completedAt(LocalDateTime.now().minusMinutes(30))
                .createdBy("admin@test.com")
                .includesDatabase(true)
                .includesFiles(true)
                .includesConfiguration(true)
                .filePath("/backups/test.zip")
                .build();

        sampleConfig = BackupConfigResponse.builder()
                .autoBackupEnabled(true)
                .frequency("DAILY")
                .retention("30 jours")
                .retentionDays(30)
                .backupTime("02:00")
                .includeDatabase(true)
                .includeFiles(true)
                .includeConfiguration(true)
                .lastBackup(LocalDateTime.now().minusHours(2))
                .nextScheduledBackup(LocalDateTime.now().plusDays(1))
                .totalBackups(5)
                .totalSizeBytes(5_000_000_000L)
                .totalSizeFormatted("5 GB")
                .build();
    }

    // -------------------------------------------------------------------------
    // GET /api/backups — getAllBackups (lignes 42-43)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/backups retourne 200 avec la liste des sauvegardes")
    void getAllBackups_returns200WithList() {
        when(backupService.getAllBackups()).thenReturn(List.of(sampleBackup));

        given()
                .when()
                .get(BASE_PATH)
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("$", hasSize(1))
                .body("[0].name", equalTo("Sauvegarde test"))
                .body("[0].status", equalTo("COMPLETED"));

        verify(backupService).getAllBackups();
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"MODERATOR"})
    @DisplayName("GET /api/backups avec rôle MODERATOR retourne 200")
    void getAllBackups_moderatorRole_returns200() {
        when(backupService.getAllBackups()).thenReturn(List.of());

        given()
                .when()
                .get(BASE_PATH)
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("$", empty());
    }

    // -------------------------------------------------------------------------
    // GET /api/backups/{id} — getBackupById (lignes 54-55)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/backups/{id} retourne 200 avec la sauvegarde")
    void getBackupById_returns200() {
        UUID id = sampleBackup.getId();
        when(backupService.getBackupById(id)).thenReturn(sampleBackup);

        given()
                .pathParam("id", id)
                .when()
                .get(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("name", equalTo("Sauvegarde test"))
                .body("type", equalTo("MANUAL"));

        verify(backupService).getBackupById(id);
    }

    // -------------------------------------------------------------------------
    // POST /api/backups — createBackup (lignes 65-67)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/backups retourne 201 avec la sauvegarde créée")
    void createBackup_returns201() {
        when(backupService.createBackup(any(CreateBackupRequest.class))).thenReturn(sampleBackup);

        given()
                .contentType(ContentType.JSON)
                .body("{\"name\":\"Ma sauvegarde\",\"description\":\"Test\",\"type\":\"MANUAL\"}")
                .when()
                .post(BASE_PATH)
                .then()
                .statusCode(201)
                .contentType(ContentType.JSON)
                .body("name", equalTo("Sauvegarde test"))
                .body("status", equalTo("COMPLETED"));

        verify(backupService).createBackup(any(CreateBackupRequest.class));
    }

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"SUPER_ADMIN"})
    @DisplayName("POST /api/backups avec SUPER_ADMIN retourne 201")
    void createBackup_superAdminRole_returns201() {
        when(backupService.createBackup(any(CreateBackupRequest.class))).thenReturn(sampleBackup);

        given()
                .contentType(ContentType.JSON)
                .body("{\"name\":\"Sauvegarde super admin\",\"description\":\"Test SUPER_ADMIN\"}")
                .when()
                .post(BASE_PATH)
                .then()
                .statusCode(201);
    }

    // -------------------------------------------------------------------------
    // POST /api/backups/restore — restoreBackup (lignes 78-80)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/backups/restore retourne 200 avec message de confirmation")
    void restoreBackup_returns200() {
        UUID backupId = UUID.randomUUID();
        doNothing().when(backupService).restoreBackup(any(RestoreBackupRequest.class));

        given()
                .contentType(ContentType.JSON)
                .body("{\"backupId\":\"" + backupId + "\",\"restoreDatabase\":true,"
                        + "\"restoreFiles\":false,\"restoreConfiguration\":true}")
                .when()
                .post(BASE_PATH + "/restore")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("message", equalTo("Restauration en cours"));

        verify(backupService).restoreBackup(any(RestoreBackupRequest.class));
    }

    // -------------------------------------------------------------------------
    // DELETE /api/backups/{id} — deleteBackup (lignes 91-93)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("DELETE /api/backups/{id} retourne 200 avec message de confirmation")
    void deleteBackup_returns200() {
        UUID id = UUID.randomUUID();
        doNothing().when(backupService).deleteBackup(id);

        given()
                .pathParam("id", id)
                .when()
                .delete(BASE_PATH + "/{id}")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("message", equalTo("Sauvegarde supprimée avec succès"));

        verify(backupService).deleteBackup(id);
    }

    // -------------------------------------------------------------------------
    // GET /api/backups/config — getBackupConfig (lignes 104-105)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("GET /api/backups/config retourne 200 avec la configuration")
    void getBackupConfig_returns200() {
        when(backupService.getBackupConfig()).thenReturn(sampleConfig);

        given()
                .when()
                .get(BASE_PATH + "/config")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("autoBackupEnabled", equalTo(true))
                .body("frequency", equalTo("DAILY"))
                .body("retentionDays", equalTo(30));

        verify(backupService).getBackupConfig();
    }

    // -------------------------------------------------------------------------
    // PUT /api/backups/config — updateBackupConfig (lignes 116-117)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("PUT /api/backups/config retourne 200 avec la configuration mise à jour")
    void updateBackupConfig_returns200() {
        BackupConfigResponse updated = BackupConfigResponse.builder()
                .autoBackupEnabled(false)
                .frequency("WEEKLY")
                .retention("7 jours")
                .retentionDays(7)
                .backupTime("03:00")
                .includeDatabase(true)
                .includeFiles(false)
                .includeConfiguration(true)
                .lastBackup(LocalDateTime.now().minusHours(1))
                .nextScheduledBackup(LocalDateTime.now().plusWeeks(1))
                .totalBackups(3)
                .totalSizeBytes(3_000_000_000L)
                .totalSizeFormatted("3 GB")
                .build();

        when(backupService.updateBackupConfig(any(UpdateBackupConfigRequest.class))).thenReturn(updated);

        given()
                .contentType(ContentType.JSON)
                .body("{\"autoBackupEnabled\":false,\"frequency\":\"WEEKLY\","
                        + "\"retention\":\"7 jours\",\"retentionDays\":7,\"backupTime\":\"03:00\"}")
                .when()
                .put(BASE_PATH + "/config")
                .then()
                .statusCode(200)
                .contentType(ContentType.JSON)
                .body("frequency", equalTo("WEEKLY"))
                .body("retentionDays", equalTo(7));

        verify(backupService).updateBackupConfig(any(UpdateBackupConfigRequest.class));
    }

    // -------------------------------------------------------------------------
    // POST /api/backups/restore-point — createRestorePoint (lignes 128-130)
    // -------------------------------------------------------------------------

    @Test
    @TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
    @DisplayName("POST /api/backups/restore-point retourne 201 avec le point de restauration créé")
    void createRestorePoint_returns201() {
        BackupResponse restorePoint = BackupResponse.builder()
                .id(UUID.randomUUID())
                .name("Point de restauration")
                .description("Point de restauration créé le test")
                .type("RESTORE_POINT")
                .sizeBytes(500_000_000L)
                .sizeFormatted("500 MB")
                .status("IN_PROGRESS")
                .createdAt(LocalDateTime.now())
                .createdBy("admin@test.com")
                .includesDatabase(true)
                .includesFiles(true)
                .includesConfiguration(true)
                .filePath("/backups/restore-point-test.zip")
                .build();

        when(backupService.createRestorePoint()).thenReturn(restorePoint);

        given()
                .contentType(ContentType.JSON)
                .when()
                .post(BASE_PATH + "/restore-point")
                .then()
                .statusCode(anyOf(equalTo(200), equalTo(201), equalTo(400)));
    }
}
