import 'dart:io';
import 'package:sqlite3/sqlite3.dart' as sql;
import 'package:path/path.dart' as p;

class TrackerDatabase {
  late final sql.Database _db;

  TrackerDatabase() {
    _init();
  }

  void _init() {
    // Ensure data directory exists
    final dataDir = Directory('data');
    if (!dataDir.existsSync()) {
      dataDir.createSync();
    }

    final dbPath = p.join('data', 'tracker.db');
    print('Opening database at $dbPath');
    _db = sql.sqlite3.open(dbPath);

    _createTables();
  }

  void _createTables() {
    print('Creating tables if not exist...');

    // Users table
    _db.execute('''
      CREATE TABLE IF NOT EXISTS users (
        id TEXT PRIMARY KEY,
        role TEXT NOT NULL,
        name TEXT,
        email TEXT,
        partner_id TEXT,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        updated_at TEXT DEFAULT CURRENT_TIMESTAMP
      )
    ''');

    // Cycle Entries table
    _db.execute('''
      CREATE TABLE IF NOT EXISTS cycle_entries (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        date TEXT NOT NULL,
        flow_intensity TEXT,
        is_period_day INTEGER DEFAULT 0,
        symptoms TEXT, -- JSON string
        moods TEXT, -- JSON string
        notes TEXT,
        updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
        UNIQUE(user_id, date)
      )
    ''');

    // Teaching Plans table
    _db.execute('''
      CREATE TABLE IF NOT EXISTS teaching_plans (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        date TEXT NOT NULL,
        topic TEXT,
        scripture_reference TEXT,
        notes TEXT,
        is_completed INTEGER DEFAULT 0,
        updated_at TEXT DEFAULT CURRENT_TIMESTAMP
      )
    ''');

    // Prayer Requests table
    _db.execute('''
      CREATE TABLE IF NOT EXISTS prayer_requests (
        id TEXT PRIMARY KEY,
        user_id TEXT NOT NULL,
        request TEXT,
        is_answered INTEGER DEFAULT 0,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        updated_at TEXT DEFAULT CURRENT_TIMESTAMP
      )
    ''');

    print('Tables created.');
  }

  // Basic CRUD placeholders for sync

  void upsertCycleEntry(String userId, Map<String, dynamic> entry) {
    // Assuming entry contains fields matching DB
    final stmt = _db.prepare('''
      INSERT OR REPLACE INTO cycle_entries (
        id, user_id, date, flow_intensity, is_period_day, symptoms, moods, notes, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
    ''');

    stmt.execute([
      entry['id'],
      userId,
      entry['date'],
      entry['flowIntensity'],
      entry['isPeriodDay'] == true ? 1 : 0,
      entry['symptoms'], // JSON
      entry['moods'], // JSON
      entry['notes'],
    ]);
    stmt.dispose();
  }

  List<Map<String, dynamic>> getCycleEntries(String userId, {String? since}) {
    // If since is provided, filter by updated_at
    // For MVP sync, we might just return all or a simple diff
    final result =
        _db.select('SELECT * FROM cycle_entries WHERE user_id = ?', [userId]);
    return result
        .map((row) => {
              'id': row['id'],
              'date': row['date'],
              'flowIntensity': row['flow_intensity'],
              'isPeriodDay': row['is_period_day'] == 1,
              'symptoms': row['symptoms'],
              'moods': row['moods'],
              'notes': row['notes'],
              'updatedAt': row['updated_at']
            })
        .toList();
  }

  // Teaching Plan operations
  void upsertTeachingPlan(String userId, Map<String, dynamic> plan) {
    final stmt = _db.prepare('''
      INSERT OR REPLACE INTO teaching_plans (
        id, user_id, date, topic, scripture_reference, notes, is_completed, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
    ''');

    stmt.execute([
      plan['id'],
      userId,
      plan['date'],
      plan['topic'],
      plan['scriptureReference'],
      plan['notes'],
      plan['isCompleted'] == true ? 1 : 0,
    ]);
    stmt.dispose();
  }

  List<Map<String, dynamic>> getTeachingPlans(String userId) {
    final result =
        _db.select('SELECT * FROM teaching_plans WHERE user_id = ?', [userId]);
    return result
        .map((row) => {
              'id': row['id'],
              'date': row['date'],
              'topic': row['topic'],
              'scriptureReference': row['scripture_reference'],
              'notes': row['notes'],
              'isCompleted': row['is_completed'] == 1,
              'updatedAt': row['updated_at']
            })
        .toList();
  }

  // Prayer Request operations
  void upsertPrayerRequest(String userId, Map<String, dynamic> request) {
    final stmt = _db.prepare('''
      INSERT OR REPLACE INTO prayer_requests (
        id, user_id, request, is_answered, created_at, updated_at
      ) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
    ''');

    stmt.execute([
      request['id'],
      userId,
      request['request'],
      request['isAnswered'] == true ? 1 : 0,
      request['createdAt'],
    ]);
    stmt.dispose();
  }

  List<Map<String, dynamic>> getPrayerRequests(String userId) {
    final result =
        _db.select('SELECT * FROM prayer_requests WHERE user_id = ?', [userId]);
    return result
        .map((row) => {
              'id': row['id'],
              'request': row['request'],
              'isAnswered': row['is_answered'] == 1,
              'createdAt': row['created_at'],
              'updatedAt': row['updated_at']
            })
        .toList();
  }

  // User operations
  void upsertUser(String userId, Map<String, dynamic> userData) {
    // Check if user exists first
    final existing = _db.select('SELECT * FROM users WHERE id = ?', [userId]);

    if (existing.isEmpty) {
      // Insert new
      final stmt = _db.prepare('''
        INSERT INTO users (
          id, role, name, email, partner_id, created_at, updated_at
        ) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
      ''');
      stmt.execute([
        userId,
        userData['role'] ?? 'wife',
        userData['name'],
        userData['email'],
        userData['partnerId'],
        userData['createdAt'] ?? DateTime.now().toIso8601String(),
      ]);
      stmt.dispose();
    } else {
      // Update existing
      // CRITICAL: Do NOT overwrite partner_id with NULL if it is already set in DB
      // unless the client specifically might intend it (which is hard to know).
      // For Safe Onboarding: If DB has a partner_id, and incoming is NULL, keep DB value.

      final row = existing.first;
      final dbPartnerId = row['partner_id'];
      final incomingPartnerId = userData['partnerId'];

      String? finalPartnerId = incomingPartnerId;
      if (incomingPartnerId == null && dbPartnerId != null) {
        finalPartnerId = dbPartnerId as String?;
      }

      final stmt = _db.prepare('''
        UPDATE users SET 
          role = ?, 
          name = ?, 
          email = ?, 
          partner_id = ?, 
          updated_at = CURRENT_TIMESTAMP 
        WHERE id = ?
      ''');
      stmt.execute([
        userData['role'] ?? row['role'],
        userData['name'] ?? row['name'],
        userData['email'] ?? row['email'],
        finalPartnerId,
        userId,
      ]);
      stmt.dispose();
    }
  }

  bool linkPartners(String userId, String targetPartnerId) {
    // 1. Verify target exists (optional, or just blindly update)
    // For MVP, just update both.

    // Update User -> Partner
    _db.execute('UPDATE users SET partner_id = ? WHERE id = ?',
        [targetPartnerId, userId]);

    // Update Partner -> User
    _db.execute('UPDATE users SET partner_id = ? WHERE id = ?',
        [userId, targetPartnerId]);

    // Check if both have partner_id set now?
    // Just return true.
    return true;
  }

  Map<String, dynamic>? getUser(String userId) {
    final result = _db.select('SELECT * FROM users WHERE id = ?', [userId]);
    if (result.isEmpty) return null;
    final row = result.first;
    return {
      'id': row['id'],
      'role': row['role'],
      'name': row['name'],
      'email': row['email'],
      'partnerId': row['partner_id'],
    };
  }
}
