/// Tests d'intégration pour Finance Workflow (API-only)
library finance_workflow_integration_test;

import 'dart:convert';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;

import 'helpers/test_config.dart';
import 'helpers/auth_helper.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  late http.Client client;
  late AuthHelper authHelper;

  setUpAll(() async {
    print('\n🚀 Démarrage des tests d\'intégration Finance Workflow\n');
    client = http.Client();
    authHelper = AuthHelper(client);

    // Authentification en tant qu'ORG_ADMIN
    final authenticated = await authHelper.authenticateAsOrgAdmin();
    expect(authenticated, true, reason: 'Authentification doit réussir');

    print('✅ Setup terminé - Token obtenu\n');
  });

  tearDownAll(() {
    client.close();
    print('\n✅ Tests d\'intégration Finance Workflow terminés\n');
  });

  group('Finance Workflow - Approbations', () {
    test('GET /api/finance/approvals/pending - Récupérer approbations en attente',
        () async {
      // Arrange
      final url = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/approvals/pending',
      ).replace(queryParameters: {
        'organizationId': TestConfig.testOrganizationId,
      });

      // Act
      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 200, reason: 'HTTP 200 OK attendu');

      final List<dynamic> approvals = json.decode(response.body);
      expect(approvals, isA<List>(), reason: 'Réponse doit être une liste');

      print('✅ GET pending approvals: ${approvals.length} approbations trouvées');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('GET /api/finance/approvals/{id} - Récupérer approbation par ID',
        () async {
      // Arrange - Récupère d'abord la liste pour avoir un ID
      final listUrl = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/approvals/pending',
      ).replace(queryParameters: {
        'organizationId': TestConfig.testOrganizationId,
      });

      final listResponse = await client.get(listUrl, headers: authHelper.getAuthHeaders());
      expect(listResponse.statusCode, 200);

      final List<dynamic> approvals = json.decode(listResponse.body);

      if (approvals.isEmpty) {
        print('⚠️  Aucune approbation en attente - test ignoré');
        return;
      }

      final approvalId = approvals.first['id'];

      // Act - Récupère l'approbation par ID
      final url = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/approvals/$approvalId',
      );

      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 200, reason: 'HTTP 200 OK attendu');

      final approval = json.decode(response.body);
      expect(approval['id'], equals(approvalId), reason: 'ID doit correspondre');

      print('✅ GET approval by ID: ${approval['id']}');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('POST /api/finance/approvals/{id}/approve - Approuver transaction',
        () async {
      // Note: Ce test nécessite une approbation en statut "pending"
      // Pour éviter de modifier l'état en prod, ce test est informatif

      print('ℹ️  Test approve transaction - Simulé (évite modification en prod)');
      print('   Endpoint: POST /api/finance/approvals/{id}/approve');
      print('   Body: { "comment": "Approved by integration test" }');
      print('   Expected: HTTP 200, statut=approved');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('POST /api/finance/approvals/{id}/reject - Rejeter transaction',
        () async {
      // Note: Ce test nécessite une approbation en statut "pending"
      // Pour éviter de modifier l'état en prod, ce test est informatif

      print('ℹ️  Test reject transaction - Simulé (évite modification en prod)');
      print('   Endpoint: POST /api/finance/approvals/{id}/reject');
      print('   Body: { "reason": "Rejected by integration test" }');
      print('   Expected: HTTP 200, statut=rejected');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });
  });

  group('Finance Workflow - Budgets', () {
    String? createdBudgetId;

    test('GET /api/finance/budgets - Récupérer liste budgets',
        () async {
      // Arrange
      final url = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/budgets',
      ).replace(queryParameters: {
        'organizationId': TestConfig.testOrganizationId,
      });

      // Act
      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 200, reason: 'HTTP 200 OK attendu');

      final List<dynamic> budgets = json.decode(response.body);
      expect(budgets, isA<List>(), reason: 'Réponse doit être une liste');

      print('✅ GET budgets: ${budgets.length} budgets trouvés');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('POST /api/finance/budgets - Créer un budget',
        () async {
      // Arrange
      final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets');

      final requestBody = {
        'name': 'Budget Test Intégration ${DateTime.now().millisecondsSinceEpoch}',
        'description': 'Budget créé par test d\'intégration',
        'organizationId': TestConfig.testOrganizationId,
        'period': 'ANNUAL',
        'year': DateTime.now().year,
        'lines': [
          {
            'category': 'CONTRIBUTIONS',
            'name': 'Cotisations',
            'amountPlanned': 1000000.0,
            'description': 'Revenus cotisations',
          },
          {
            'category': 'SAVINGS',
            'name': 'Épargne',
            'amountPlanned': 500000.0,
            'description': 'Collecte épargne',
          },
        ],
      };

      // Act
      final response = await client.post(
        url,
        headers: authHelper.getAuthHeaders(),
        body: json.encode(requestBody),
      );

      // Assert
      expect(response.statusCode, inInclusiveRange(200, 201),
          reason: 'HTTP 200/201 attendu');

      final budget = json.decode(response.body);
      expect(budget['id'], isNotNull, reason: 'ID budget doit être présent');
      expect(budget['name'], contains('Budget Test Intégration'),
          reason: 'Nom doit correspondre');

      createdBudgetId = budget['id'];
      print('✅ POST create budget: ${budget['id']} - ${budget['name']}');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('GET /api/finance/budgets/{id} - Récupérer budget par ID',
        () async {
      // Arrange - Utilise le budget créé précédemment ou récupère un existant
      String budgetId;

      if (createdBudgetId != null) {
        budgetId = createdBudgetId!;
      } else {
        // Récupère un budget existant
        final listUrl = Uri.parse(
          '${TestConfig.apiBaseUrl}/api/finance/budgets',
        ).replace(queryParameters: {
          'organizationId': TestConfig.testOrganizationId,
        });

        final listResponse = await client.get(listUrl, headers: authHelper.getAuthHeaders());
        expect(listResponse.statusCode, 200);

        final List<dynamic> budgets = json.decode(listResponse.body);
        if (budgets.isEmpty) {
          print('⚠️  Aucun budget trouvé - test ignoré');
          return;
        }

        budgetId = budgets.first['id'];
      }

      // Act
      final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets/$budgetId');
      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 200, reason: 'HTTP 200 OK attendu');

      final budget = json.decode(response.body);
      expect(budget['id'], equals(budgetId), reason: 'ID doit correspondre');
      expect(budget['lines'], isNotNull, reason: 'Lignes budgétaires doivent être présentes');

      print('✅ GET budget by ID: ${budget['id']} - ${budget['name']}');
      print('   Lignes budgétaires: ${budget['lines'].length}');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });
  });

  group('Finance Workflow - Tests négatifs', () {
    test('GET approbation inexistante - Doit retourner 404',
        () async {
      // Arrange
      final fakeId = '00000000-0000-0000-0000-000000000000';
      final url = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/approvals/$fakeId',
      );

      // Act
      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 404, reason: 'HTTP 404 Not Found attendu');

      print('✅ Test négatif: 404 pour approbation inexistante');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('GET budget inexistant - Doit retourner 404',
        () async {
      // Arrange
      final fakeId = '00000000-0000-0000-0000-000000000000';
      final url = Uri.parse(
        '${TestConfig.apiBaseUrl}/api/finance/budgets/$fakeId',
      );

      // Act
      final response = await client.get(url, headers: authHelper.getAuthHeaders());

      // Assert
      expect(response.statusCode, 404, reason: 'HTTP 404 Not Found attendu');

      print('✅ Test négatif: 404 pour budget inexistant');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });

    test('POST budget sans authentication - Doit retourner 401',
        () async {
      // Arrange
      final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/budgets');
      final requestBody = {
        'name': 'Budget Sans Auth',
        'organizationId': TestConfig.testOrganizationId,
        'period': 'ANNUAL',
        'year': 2026,
        'lines': [],
      };

      // Act - Sans token d'authentification
      final response = await client.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: json.encode(requestBody),
      );

      // Assert
      expect(response.statusCode, 401, reason: 'HTTP 401 Unauthorized attendu');

      print('✅ Test négatif: 401 pour requête non authentifiée');

      await Future.delayed(Duration(milliseconds: TestConfig.delayBetweenTests));
    });
  });
}
