import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:bcrypt/bcrypt.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:dotenv/dotenv.dart';
import '../database/database_provider.dart';
import '../middleware/auth_middleware.dart';
import '../middleware/request_logger.dart';
import 'dart:convert';

class AuthRoutes {
  final DatabaseProvider database;

  AuthRoutes(this.database);

  Router get routes {
    final router = Router();
    router.post('/login', _login);
    router.post('/reg', _register);
    router.get('/watch', AuthMiddleware(_watch).call);
    return router;
  }

  Future<Response> _login(Request request) async {
    final body = await request.readAsString();
    final data = jsonDecode(body);

    final login = data['login'];
    final password = data['password'];

    final user = await database.findUserByLogin(login);

    final stopwatch = Stopwatch()..start();
    if (user == null || !BCrypt.checkpw(password, user.pwdHash)) {
      await database.createLog(login, 'Failed login attempt');
      stopwatch.stop();
      final response = Response(401, body: jsonEncode({'error': 'Invalid credentials'}), headers: {'Content-Type': 'application/json'});
      logRequest(method: 'POST', url: '/login', status: 401, duration: stopwatch.elapsed, body: body, responseHeaders: response.headers);
      return response;
    }

    // Генерация JWT токена
    final dotenv = DotEnv();
    final secret = dotenv['JWT_SECRET'] ?? '';
    final jwt = JWT(
      {'user_id': user.id, 'login': user.login},
      issuer: 'family_safety_tracker'
    );
    final token = jwt.sign(SecretKey(secret));

    await database.createLog(login, 'Successful login');
    stopwatch.stop();
    final response = Response(200, body: jsonEncode({'token': token}), headers: {'Content-Type': 'application/json'});
    logRequest(method: 'POST', url: '/login', status: 200, duration: stopwatch.elapsed, body: body, responseHeaders: response.headers);
    return response;
  }

  Future<Response> _register(Request request) async {
    final stopwatch = Stopwatch()..start();
    final body = await request.readAsString();
    final data = jsonDecode(body);

    final login = data['login'];
    final password = data['password'];

    await database.createUser(login, password);
    await database.createLog(login, 'User registration');
    stopwatch.stop();
    final response = Response(201, body: jsonEncode({'message': 'User registered'}), headers: {'Content-Type': 'application/json'});
    logRequest(method: 'POST', url: '/reg', status: 201, duration: stopwatch.elapsed, body: body, responseHeaders: response.headers);
    return response;
  }

  Future<Response> _watch(Request request, String login) async {
    final stopwatch = Stopwatch()..start();
    final uniqueId = request.url.queryParameters['share_id'];
    if (uniqueId == null) {
      stopwatch.stop();
      final response = Response(404, body: jsonEncode({'error': 'Share link not found'}), headers: {'Content-Type': 'application/json'});
      logRequest(method: 'GET', url: '/watch', status: 404, duration: stopwatch.elapsed, responseHeaders: response.headers);
      return response;
    }

    final geoId = database.getGeoIdByShareId(uniqueId);

    if (geoId == null) {
      await database.createLog(login, 'Accessed invalid share link');
      stopwatch.stop();
      final response = Response(404, body: jsonEncode({'error': 'Share link not found'}), headers: {'Content-Type': 'application/json'});
      logRequest(method: 'GET', url: '/watch', status: 404, duration: stopwatch.elapsed, responseHeaders: response.headers);
      return response;
    }

    final position = await database.getPositionById(geoId);

    if (position == null) {
      await database.createLog(login, 'Accessed share link - no position');
      stopwatch.stop();
      final response = Response(404, body: jsonEncode({'error': 'No position available'}), headers: {'Content-Type': 'application/json'});
      logRequest(method: 'GET', url: '/watch', status: 404, duration: stopwatch.elapsed, responseHeaders: response.headers);
      return response;
    }

    await database.createLog(login, 'Accessed share link');
    stopwatch.stop();
    final response = Response(200, body: jsonEncode({
      'x': position.xValue,
      'y': position.yValue,
      'last_update': position.lastUpdate.toIso8601String(),
      'expires_at': position.expiresAt.toIso8601String(),
    }), headers: {'Content-Type': 'application/json'});
    logRequest(method: 'GET', url: '/watch', status: 200, duration: stopwatch.elapsed, responseHeaders: response.headers);
    return response;
  }
}