/// Integration tests for 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=== Finance Workflow Integration Tests ===\n');
    client = http.Client();
    authHelper = AuthHelper(client);

    // Authenticate as ORG_ADMIN
    final authenticated = await authHelper.authenticateAsOrgAdmin();
    expect(authenticated, true, reason: 'Authentication must succeed');

    print('Setup complete - Token obtained\n');
  });

  tearDownAll(() {
    client.close();
    print('\n=== Integration Tests Completed ===\n');
  });

  group('Finance Workflow - Approvals', () {
    test('GET /api/finance/approvals/pending - List pending approvals', () async {
      final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/pending')
          .replace(queryParameters: {'organizationId': TestConfig.testOrganizationId});

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

      expect(response.statusCode, 200, reason: 'HTTP 200 OK expected');

      final List<dynamic> approvals = json.decode(response.body);
      expect(approvals, isA<List>(), reason: 'Response must be a list');

      print('GET pending approvals: ${approvals.length} found');

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

    test('GET /api/finance/approvals/{id} - Get approval by ID', () async {
      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('No pending approvals - test skipped');
        return;
      }

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

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

      expect(response.statusCode, 200, reason: 'HTTP 200 OK expected');

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

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

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

    test('POST /api/finance/approvals/{id}/approve - Approve transaction (simulated)', () async {
      print('Test approve transaction - Simulated (avoids prod modification)');
      print('   Endpoint: POST /api/finance/approvals/{id}/approve');
      print('   Body: { "comment": "Approved by integration test" }');
      print('   Expected: HTTP 200, status=approved');

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

    test('POST /api/finance/approvals/{id}/reject - Reject transaction (simulated)', () async {
      print('Test reject transaction - Simulated (avoids prod modification)');
      print('   Endpoint: POST /api/finance/approvals/{id}/reject');
      print('   Body: { "reason": "Rejected by integration test" }');
      print('   Expected: HTTP 200, status=rejected');

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

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

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

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

      expect(response.statusCode, 200, reason: 'HTTP 200 OK expected');

      final List<dynamic> budgets = json.decode(response.body);
      expect(budgets, isA<List>(), reason: 'Response must be a list');

      print('GET budgets: ${budgets.length} found');

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

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

      final requestBody = {
        'name': 'Budget Integration Test ${DateTime.now().millisecondsSinceEpoch}',
        'description': 'Budget created by integration test',
        'organizationId': TestConfig.testOrganizationId,
        'period': 'ANNUAL',
        'year': DateTime.now().year,
        'lines': [
          {
            'category': 'CONTRIBUTIONS',
            'name': 'Contributions',
            'amountPlanned': 1000000.0,
            'description': 'Membership contributions',
          },
          {
            'category': 'SAVINGS',
            'name': 'Savings',
            'amountPlanned': 500000.0,
            'description': 'Savings collection',
          },
        ],
      };

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

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

      final budget = json.decode(response.body);
      expect(budget['id'], isNotNull, reason: 'Budget ID must be present');
      expect(budget['name'], contains('Budget Integration Test'), reason: 'Name must match');

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

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

    test('GET /api/finance/budgets/{id} - Get budget by ID', () async {
      String budgetId;

      if (createdBudgetId != null) {
        budgetId = createdBudgetId!;
      } else {
        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('No budgets found - test skipped');
          return;
        }

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

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

      expect(response.statusCode, 200, reason: 'HTTP 200 OK expected');

      final budget = json.decode(response.body);
      expect(budget['id'], equals(budgetId), reason: 'ID must match');
      expect(budget['lines'], isNotNull, reason: 'Budget lines must be present');

      print('GET budget by ID: ${budget['id']} - ${budget['name']}');
      print('   Budget lines: ${budget['lines'].length}');

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

  group('Finance Workflow - Negative Tests', () {
    test('GET nonexistent approval - Should return 404', () async {
      final fakeId = '00000000-0000-0000-0000-000000000000';
      final url = Uri.parse('${TestConfig.apiBaseUrl}/api/finance/approvals/$fakeId');

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

      expect(response.statusCode, 404, reason: 'HTTP 404 Not Found expected');

      print('Negative test: 404 for nonexistent approval');

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

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

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

      expect(response.statusCode, 404, reason: 'HTTP 404 Not Found expected');

      print('Negative test: 404 for nonexistent budget');

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

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

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

      expect(response.statusCode, 401, reason: 'HTTP 401 Unauthorized expected');

      print('Negative test: 401 for unauthenticated request');

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