import 'dart:io';
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_router/shelf_router.dart';
import 'package:tracker_backend/database.dart';

void main(List<String> args) async {
  // Use port 8090 as requested
  final port = 8090;
  final db = TrackerDatabase();

  final app = Router();

  app.get('/', (Request request) {
    return Response.ok('Tracker Sync Server Running');
  });

  // Handle CORS Preflight (OPTIONS) for all routes
  app.add('OPTIONS', r'/<ignored|.*>', (Request request) {
    return Response.ok('', headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
      'Access-Control-Allow-Headers': 'Origin, Content-Type',
    });
  });

  // Sync Push Endpoint
  // Expects JSON: { "userId": "...", "entries": [], "teachingPlans": [], "prayerRequests": [] }
  app.post('/sync/push', (Request request) async {
    try {
      final payload = await request.readAsString();
      final data = jsonDecode(payload);
      final userId = data['userId'];

      // 0. Update User Record
      // We expect 'userDetails' in payload now, but handle legacy
      if (data.containsKey('userDetails')) {
        db.upsertUser(userId, data['userDetails']);
      } else {
        // Fallback: create basic record if missing?
        // Or just let it fail if we need linking.
        // We'll trust frontend sends it now.
      }

      // 1. Cycle Entries
      final entries = data['entries'] as List? ?? [];
      for (var entry in entries) {
        db.upsertCycleEntry(userId, entry);
      }

      // 2. Teaching Plans
      final teachingPlans = data['teachingPlans'] as List? ?? [];
      for (var plan in teachingPlans) {
        db.upsertTeachingPlan(userId, plan);
      }

      // 3. Prayer Requests
      final prayerRequests = data['prayerRequests'] as List? ?? [];
      for (var req in prayerRequests) {
        db.upsertPrayerRequest(userId, req);
      }

      print(
          'Synced for $userId: ${entries.length} entries, ${teachingPlans.length} plans, ${prayerRequests.length} prayers');

      return Response.ok(jsonEncode({'status': 'success'}));
    } catch (e) {
      print('Sync Error: $e');
      return Response.internalServerError(body: 'Sync Failed: $e');
    }
  });

  // Preview Link Endpoint
  // POST /sync/preview
  // Body: { "targetId": "..." }
  // Returns: { "name": "...", "role": "..." }
  app.post('/sync/preview', (Request request) async {
    try {
      final payload = await request.readAsString();
      final data = jsonDecode(payload);
      final targetId = data['targetId'];

      if (targetId == null) {
        return Response.badRequest(body: 'Missing targetId');
      }

      final targetUser = db.getUser(targetId);
      if (targetUser == null) {
        return Response.notFound(jsonEncode({'error': 'Partner ID not found'}));
      }

      return Response.ok(jsonEncode({
        'status': 'success',
        'partnerName': targetUser['name'],
        'partnerRole': targetUser['role'],
      }));
    } catch (e) {
      print('Preview Error: $e');
      return Response.internalServerError(body: 'Preview Failed: $e');
    }
  });

  // Link Endpoint
  // POST /sync/link
  // Body: { "userId": "...", "targetId": "..." }
  app.post('/sync/link', (Request request) async {
    try {
      final payload = await request.readAsString();
      final data = jsonDecode(payload);
      final userId = data['userId'];
      final targetId = data['targetId'];

      if (userId == null || targetId == null) {
        return Response.badRequest(body: 'Missing userId or targetId');
      }

      // Verify target exists
      final targetUser = db.getUser(targetId);
      if (targetUser == null) {
        return Response.notFound(jsonEncode({'error': 'Partner ID not found'}));
      }

      // Perform Link
      db.linkPartners(userId, targetId);

      // Return partner name/info
      return Response.ok(jsonEncode({
        'status': 'success',
        'partnerName': targetUser['name'],
        'partnerEmail': targetUser['email']
      }));
    } catch (e) {
      print('Link Error: $e');
      return Response.internalServerError(body: 'Link Failed: $e');
    }
  });

  // Pull Endpoint
  // GET /sync/pull?userId=...&partnerId=...
  app.get('/sync/pull', (Request request) {
    final userId = request.url.queryParameters['userId'];
    final partnerId = request.url.queryParameters['partnerId'];

    if (userId == null) return Response.badRequest(body: 'Missing userId');

    // 1. Get My Data
    final myEntries = db.getCycleEntries(userId);
    final myPlans = db.getTeachingPlans(userId); // Plans I created
    final myPrayers = db.getPrayerRequests(userId); // Prayers I created

    // 2. Get Partner Data (if linked)
    List<Map<String, dynamic>> partnerEntries = [];
    List<Map<String, dynamic>> partnerPlans = [];
    List<Map<String, dynamic>> partnerPrayers = [];

    if (partnerId != null && partnerId.isNotEmpty) {
      // Fetch partner's cycle entries
      partnerEntries = db.getCycleEntries(partnerId);

      // Fetch plans created by partner (e.g. Husband created plans for Wife to see)
      partnerPlans = db.getTeachingPlans(partnerId);

      // Fetch partner's prayer requests
      partnerPrayers = db.getPrayerRequests(partnerId);
    }

    // 3. Get User Profile (to sync back partner changes)
    final userProfile = db.getUser(userId);

    // Combine Data
    final responseData = {
      'entries': [...myEntries, ...partnerEntries],
      // Teaching Plans: I want to see my own AND my partner's
      'teachingPlans': [...myPlans, ...partnerPlans],
      // Prayer Requests: I want to see my own AND my partner's
      'prayerRequests': [...myPrayers, ...partnerPrayers],
      if (userProfile != null) 'userProfile': userProfile,
    };

    return Response.ok(jsonEncode(responseData));
  });

  // Enable CORS
  final handler = Pipeline().addMiddleware((innerHandler) {
    return (request) async {
      final response = await innerHandler(request);
      return response.change(headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Origin, Content-Type',
      });
    };
  }).addHandler(app);

  final server = await io.serve(handler, InternetAddress.anyIPv4, port);
  print('Server running on localhost:${server.port}');
}
