import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:test/test.dart';

void main() {
  final port = '9090';
  final host = 'http://localhost:$port';
  late Process p;
  String? authToken;

  Future<String?> getAuthToken() async {
    if (authToken != null) return authToken;

    final regResponse = await http.post(
      Uri.parse('$host/reg'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'login': 'testuser', 'password': 'testpass'}),
    );

    final loginResponse = await http.post(
      Uri.parse('$host/login'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'login': 'testuser', 'password': 'testpass'}),
    );

    if (loginResponse.statusCode == 200) {
      final data = jsonDecode(loginResponse.body) as Map<String, dynamic>;
      authToken = data['token'];
    }
    return authToken;
  }

  setUpAll(() async {
    stdout.writeln("Starting server...");
    p = await Process.start(
      'dart',
      ['run', 'bin/server.dart'],
      environment: {'PORT': port},
    );

    // Wait for server to be ready
    for (int i = 0; i < 30; i++) {
      try {
        final response = await http.get(Uri.parse('$host/'));
        if (response.statusCode == 200) break;
      } catch (e) {
        // Server not ready yet
      }
      await Future.delayed(Duration(seconds: 1));
    }
    stdout.writeln("Server ready");
  });

  tearDownAll(() {
    p.kill();
  });

  group('Root endpoint', () {
    test('GET / - Root endpoint', () async {
      final response = await http.get(Uri.parse('$host/'));
      expect(response.statusCode, 200);
      expect(response.body, contains('Family Safety Tracker API'));
    });

    test('GET /nonexistent - 404', () async {
      final response = await http.get(Uri.parse('$host/nonexistent'));
      expect(response.statusCode, 404);
    });
  });

  group('User registration', () {
    test('POST /reg - Register new user', () async {
      final response = await http.post(
        Uri.parse('$host/reg'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'login': 'newuser', 'password': 'newpass'}),
      );
      expect(response.statusCode, 201);
      final data = jsonDecode(response.body);
      expect(data['login'], 'newuser');
    });
  });

  group('Authentication', () {
    test('POST /login - Valid credentials', () async {
      await getAuthToken();
      expect(authToken, isNotEmpty);
    });

    test('POST /login - Invalid credentials', () async {
      final response = await http.post(
        Uri.parse('$host/login'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'login': 'testuser', 'password': 'wrongpass'}),
      );
      expect(response.statusCode, 401);
    });
  });

  group('Geo operations', () {
    test('POST /share - Create share link', () async {
      await getAuthToken();
      final response = await http.post(
        Uri.parse('$host/share'),
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer $authToken',
        },
        body: jsonEncode({'x': 40.7128, 'y': -74.006}),
      );
      expect(response.statusCode, 201);
      final data = jsonDecode(response.body);
      expect(data['share_id'], isA<String>());
    });

    test('POST /share - No auth token', () async {
      final response = await http.post(
        Uri.parse('$host/share'),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'x': 40.7128, 'y': -74.006}),
      );
      expect(response.statusCode, 401);
    });
  });

  group('Watch endpoint', () {
    test('GET /watch - Invalid share link', () async {
      final response = await http.get(
        Uri.parse('$host/watch?unique_id=invalid-uuid'),
      );
      expect(response.statusCode, 404);
    });
  });
}