// lib/services/api_service.dart

import 'dart:io';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';

import 'package:environment_monitoring_app/services/base_api_service.dart';

// =======================================================================
// Part 1: Unified API Service
// =======================================================================

/// A unified service that consolidates all API interactions for the application.
/// It is organized by feature (e.g., marine, river) for clarity and provides
/// a central point for data synchronization.
class ApiService {
  final BaseApiService _baseService = BaseApiService();
  final DatabaseHelper _dbHelper = DatabaseHelper();

  late final MarineApiService marine;
  late final RiverApiService river;
  late final AirApiService air;

  static const String imageBaseUrl = 'https://dev14.pstw.com.my/';

  ApiService() {
    marine = MarineApiService(_baseService);
    river = RiverApiService(_baseService);
    air = AirApiService(_baseService);
  }

  // --- Core API Methods ---

  Future<Map<String, dynamic>> login(String email, String password) {
    return _baseService.post('auth/login', {'email': email, 'password': password});
  }

  Future<Map<String, dynamic>> register({
    required String username,
    String? firstName,
    String? lastName,
    required String email,
    required String password,
    String? phoneNumber,
    int? departmentId,
    int? companyId,
    int? positionId,
  }) {
    final Map<String, dynamic> body = {
      'username': username,
      'email': email,
      'password': password,
      'first_name': firstName ?? '',
      'last_name': lastName ?? '',
      'phone_number': phoneNumber ?? '',
      'department_id': departmentId,
      'company_id': companyId,
      'position_id': positionId,
    };
    body.removeWhere((key, value) => value == null);
    return _baseService.post('auth/register', body);
  }

  Future<Map<String, dynamic>> post(String endpoint, Map<String, dynamic> data) {
    return _baseService.post(endpoint, data);
  }

  Future<Map<String, dynamic>> getProfile() => _baseService.get('profile');
  Future<Map<String, dynamic>> getAllUsers() => _baseService.get('users');

  Future<Map<String, dynamic>> getAllDepartments() => _baseService.get('departments');
  Future<Map<String, dynamic>> getAllCompanies() => _baseService.get('companies');
  Future<Map<String, dynamic>> getAllPositions() => _baseService.get('positions');
  Future<Map<String, dynamic>> getAllStates() => _baseService.get('states');


  Future<Map<String, dynamic>> sendTelegramAlert({
    required String chatId,
    required String message,
  }) {
    return _baseService.post('marine/telegram-alert', {
      'chat_id': chatId,
      'message': message,
    });
  }

  Future<File?> downloadProfilePicture(String imageUrl, String localPath) async {
    try {
      final response = await http.get(Uri.parse(imageUrl));
      if (response.statusCode == 200) {
        final File file = File(localPath);
        await file.parent.create(recursive: true);
        await file.writeAsBytes(response.bodyBytes);
        return file;
      }
    } catch (e) {
      debugPrint('Error downloading profile picture: $e');
    }
    return null;
  }

  Future<Map<String, dynamic>> uploadProfilePicture(File imageFile) {
    return _baseService.postMultipart(
        endpoint: 'profile/upload-picture',
        fields: {},
        files: {'profile_picture': imageFile}
    );
  }

  Future<Map<String, dynamic>> refreshProfile() async {
    debugPrint('ApiService: Refreshing profile data from server...');
    final result = await getProfile();
    if (result['success'] == true && result['data'] != null) {
      await _dbHelper.saveProfile(result['data']);
      debugPrint('ApiService: Profile data refreshed and saved to local DB.');
    }
    return result;
  }


  /// Orchestrates a full data sync from the server to the local database.
  Future<Map<String, dynamic>> syncAllData() async {
    debugPrint('ApiService: Starting full data sync from server...');
    try {
      final results = await Future.wait([
        getProfile(),
        getAllUsers(),
        marine.getTarballStations(),
        marine.getManualStations(),
        marine.getTarballClassifications(),
        river.getManualStations(),
        river.getTriennialStations(),
        getAllDepartments(),
        getAllCompanies(),
        getAllPositions(),
        air.getManualStations(),
        air.getClients(),
        getAllStates(),
      ]);

      final Map<String, dynamic> syncedData = {
        'profile': results[0]['success'] == true ? results[0]['data'] : null,
        'allUsers': results[1]['success'] == true ? results[1]['data'] : null,
        'tarballStations': results[2]['success'] == true ? results[2]['data'] : null,
        'manualStations': results[3]['success'] == true ? results[3]['data'] : null,
        'tarballClassifications': results[4]['success'] == true ? results[4]['data'] : null,
        'riverManualStations': results[5]['success'] == true ? results[5]['data'] : null,
        'riverTriennialStations': results[6]['success'] == true ? results[6]['data'] : null,
        'departments': results[7]['success'] == true ? results[7]['data'] : null,
        'companies': results[8]['success'] == true ? results[8]['data'] : null,
        'positions': results[9]['success'] == true ? results[9]['data'] : null,
        'airManualStations': results[10]['success'] == true ? results[10]['data'] : null,
        'airClients': results[11]['success'] == true ? results[11]['data'] : null,
        'states': results[12]['success'] == true ? results[12]['data'] : null,
      };

      if (syncedData['profile'] != null) await _dbHelper.saveProfile(syncedData['profile']);
      if (syncedData['allUsers'] != null) await _dbHelper.saveUsers(List<Map<String, dynamic>>.from(syncedData['allUsers']));
      if (syncedData['tarballStations'] != null) await _dbHelper.saveTarballStations(List<Map<String, dynamic>>.from(syncedData['tarballStations']));
      if (syncedData['manualStations'] != null) await _dbHelper.saveManualStations(List<Map<String, dynamic>>.from(syncedData['manualStations']));
      if (syncedData['tarballClassifications'] != null) await _dbHelper.saveTarballClassifications(List<Map<String, dynamic>>.from(syncedData['tarballClassifications']));
      if (syncedData['riverManualStations'] != null) await _dbHelper.saveRiverManualStations(List<Map<String, dynamic>>.from(syncedData['riverManualStations']));
      if (syncedData['riverTriennialStations'] != null) await _dbHelper.saveRiverTriennialStations(List<Map<String, dynamic>>.from(syncedData['riverTriennialStations']));
      if (syncedData['departments'] != null) await _dbHelper.saveDepartments(List<Map<String, dynamic>>.from(syncedData['departments']));
      if (syncedData['companies'] != null) await _dbHelper.saveCompanies(List<Map<String, dynamic>>.from(syncedData['companies']));
      if (syncedData['positions'] != null) await _dbHelper.savePositions(List<Map<String, dynamic>>.from(syncedData['positions']));
      if (syncedData['airManualStations'] != null) await _dbHelper.saveAirManualStations(List<Map<String, dynamic>>.from(syncedData['airManualStations']));
      if (syncedData['airClients'] != null) await _dbHelper.saveAirClients(List<Map<String, dynamic>>.from(syncedData['airClients']));
      if (syncedData['states'] != null) await _dbHelper.saveStates(List<Map<String, dynamic>>.from(syncedData['states']));

      debugPrint('ApiService: Sync complete. Data saved to local DB.');
      return {'success': true, 'data': syncedData};

    } catch (e) {
      debugPrint('ApiService: Full data sync failed: $e');
      return {'success': false, 'message': 'Data sync failed: $e'};
    }
  }
}

// =======================================================================
// Part 2: Feature-Specific API Services
// =======================================================================

class AirApiService {
  final BaseApiService _baseService;
  AirApiService(this._baseService);

  Future<Map<String, dynamic>> getManualStations() => _baseService.get('air/manual-stations');
  Future<Map<String, dynamic>> getClients() => _baseService.get('air/clients');

  // NEW: Added dedicated method for uploading installation images
  Future<Map<String, dynamic>> uploadInstallationImages({
    required String airManId,
    required Map<String, File> files,
  }) {
    return _baseService.postMultipart(
      endpoint: 'air/manual/installation-images',
      fields: {'air_man_id': airManId},
      files: files,
    );
  }

  // NECESSARY FIX: Added dedicated method for uploading collection images
  Future<Map<String, dynamic>> uploadCollectionImages({
    required String airManId,
    required Map<String, File> files,
  }) {
    return _baseService.postMultipart(
      // Note: Please verify this endpoint path with your backend developer.
      endpoint: 'air/manual/collection-images',
      fields: {'air_man_id': airManId},
      files: files,
    );
  }
}


class MarineApiService {
  final BaseApiService _baseService;
  MarineApiService(this._baseService);

  Future<Map<String, dynamic>> getTarballStations() => _baseService.get('marine/tarball/stations');
  Future<Map<String, dynamic>> getManualStations() => _baseService.get('marine/manual/stations');
  Future<Map<String, dynamic>> getTarballClassifications() => _baseService.get('marine/tarball/classifications');

  Future<Map<String, dynamic>> submitTarballSample({
    required Map<String, String> formData,
    required Map<String, File?> imageFiles,
  }) async {
    final dataResult = await _baseService.post('marine/tarball/sample', formData);
    if (dataResult['success'] != true) return {'status': 'L1', 'success': false, 'message': 'Failed to submit data: ${dataResult['message']}'};

    final recordId = dataResult['data']?['autoid'];
    if (recordId == null) return {'status': 'L2', 'success': false, 'message': 'Data submitted, but failed to get a record ID.'};

    final filesToUpload = <String, File>{};
    imageFiles.forEach((key, value) { if (value != null) filesToUpload[key] = value; });

    if (filesToUpload.isEmpty) return {'status': 'L3', 'success': true, 'message': 'Data submitted successfully.', 'reportId': recordId};

    final imageResult = await _baseService.postMultipart(endpoint: 'marine/tarball/images', fields: {'autoid': recordId.toString()}, files: filesToUpload);
    if (imageResult['success'] != true) return {'status': 'L2', 'success': false, 'message': 'Data submitted, but image upload failed: ${imageResult['message']}', 'reportId': recordId};

    return {'status': 'L3', 'success': true, 'message': 'Data and images submitted successfully.', 'reportId': recordId};
  }
}

class RiverApiService {
  final BaseApiService _baseService;
  RiverApiService(this._baseService);

  Future<Map<String, dynamic>> getManualStations() => _baseService.get('river/manual-stations');
  Future<Map<String, dynamic>> getTriennialStations() => _baseService.get('river/triennial-stations');
}

// =======================================================================
// Part 3: Local Database Helper
// =======================================================================

class DatabaseHelper {
  static Database? _database;
  static const String _dbName = 'app_data.db';
  static const int _dbVersion = 12;

  static const String _profileTable = 'user_profile';
  static const String _usersTable = 'all_users';
  static const String _tarballStationsTable = 'marine_tarball_stations';
  static const String _manualStationsTable = 'marine_manual_stations';
  static const String _riverManualStationsTable = 'river_manual_stations';
  static const String _riverTriennialStationsTable = 'river_triennial_stations';
  static const String _tarballClassificationsTable = 'marine_tarball_classifications';
  static const String _departmentsTable = 'departments';
  static const String _companiesTable = 'companies';
  static const String _positionsTable = 'positions';
  static const String _alertQueueTable = 'alert_queue';
  static const String _airManualStationsTable = 'air_manual_stations';
  static const String _airClientsTable = 'air_clients';
  static const String _statesTable = 'states';


  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB();
    return _database!;
  }

  Future<Database> _initDB() async {
    String dbPath = p.join(await getDatabasesPath(), _dbName);
    return await openDatabase(dbPath, version: _dbVersion, onCreate: _onCreate, onUpgrade: _onUpgrade);
  }

  Future _onCreate(Database db, int version) async {
    await db.execute('CREATE TABLE $_profileTable(user_id INTEGER PRIMARY KEY, profile_json TEXT)');
    await db.execute('CREATE TABLE $_usersTable(user_id INTEGER PRIMARY KEY, user_json TEXT)');
    await db.execute('CREATE TABLE $_tarballStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
    await db.execute('CREATE TABLE $_manualStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
    await db.execute('CREATE TABLE $_riverManualStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
    await db.execute('CREATE TABLE $_riverTriennialStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
    await db.execute('CREATE TABLE $_tarballClassificationsTable(classification_id INTEGER PRIMARY KEY, classification_json TEXT)');
    await db.execute('CREATE TABLE $_departmentsTable(department_id INTEGER PRIMARY KEY, department_json TEXT)');
    await db.execute('CREATE TABLE $_companiesTable(company_id INTEGER PRIMARY KEY, company_json TEXT)');
    await db.execute('CREATE TABLE $_positionsTable(position_id INTEGER PRIMARY KEY, position_json TEXT)');
    await db.execute('''CREATE TABLE $_alertQueueTable (id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id TEXT NOT NULL, message TEXT NOT NULL, created_at TEXT NOT NULL)''');
    await db.execute('CREATE TABLE $_airManualStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
    await db.execute('CREATE TABLE $_airClientsTable(client_id INTEGER PRIMARY KEY, client_json TEXT)');
    await db.execute('CREATE TABLE $_statesTable(state_id INTEGER PRIMARY KEY, state_json TEXT)');
  }

  Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
    if (oldVersion < 11) {
      await db.execute('CREATE TABLE IF NOT EXISTS $_airManualStationsTable(station_id INTEGER PRIMARY KEY, station_json TEXT)');
      await db.execute('CREATE TABLE IF NOT EXISTS $_airClientsTable(client_id INTEGER PRIMARY KEY, client_json TEXT)');
    }
    if (oldVersion < 12) {
      await db.execute('CREATE TABLE IF NOT EXISTS $_statesTable(state_id INTEGER PRIMARY KEY, state_json TEXT)');
    }
  }

  Future<void> _saveData(String table, String idKey, List<Map<String, dynamic>> data) async {
    final db = await database;
    await db.delete(table);
    for (var item in data) {
      await db.insert(table, {'${idKey}_id': item['${idKey}_id'], '${idKey}_json': jsonEncode(item)}, conflictAlgorithm: ConflictAlgorithm.replace);
    }
  }

  Future<List<Map<String, dynamic>>?> _loadData(String table, String idKey) async {
    final db = await database;
    final List<Map<String, dynamic>> maps = await db.query(table);
    if (maps.isNotEmpty) {
      return maps.map((map) => jsonDecode(map['${idKey}_json']) as Map<String, dynamic>).toList();
    }
    return null;
  }

  Future<void> saveProfile(Map<String, dynamic> profile) async {
    final db = await database;
    await db.insert(_profileTable, {'user_id': profile['user_id'], 'profile_json': jsonEncode(profile)}, conflictAlgorithm: ConflictAlgorithm.replace);
  }
  Future<Map<String, dynamic>?> loadProfile() async {
    final db = await database;
    final List<Map<String, dynamic>> maps = await db.query(_profileTable);
    if(maps.isNotEmpty) return jsonDecode(maps.first['profile_json']);
    return null;
  }

  Future<void> saveUsers(List<Map<String, dynamic>> users) => _saveData(_usersTable, 'user', users);
  Future<List<Map<String, dynamic>>?> loadUsers() => _loadData(_usersTable, 'user');

  Future<void> saveTarballStations(List<Map<String, dynamic>> stations) => _saveData(_tarballStationsTable, 'station', stations);
  Future<List<Map<String, dynamic>>?> loadTarballStations() => _loadData(_tarballStationsTable, 'station');

  Future<void> saveManualStations(List<Map<String, dynamic>> stations) => _saveData(_manualStationsTable, 'station', stations);
  Future<List<Map<String, dynamic>>?> loadManualStations() => _loadData(_manualStationsTable, 'station');

  Future<void> saveRiverManualStations(List<Map<String, dynamic>> stations) => _saveData(_riverManualStationsTable, 'station', stations);
  Future<List<Map<String, dynamic>>?> loadRiverManualStations() => _loadData(_riverManualStationsTable, 'station');

  Future<void> saveRiverTriennialStations(List<Map<String, dynamic>> stations) => _saveData(_riverTriennialStationsTable, 'station', stations);
  Future<List<Map<String, dynamic>>?> loadRiverTriennialStations() => _loadData(_riverTriennialStationsTable, 'station');

  Future<void> saveTarballClassifications(List<Map<String, dynamic>> data) => _saveData(_tarballClassificationsTable, 'classification', data);
  Future<List<Map<String, dynamic>>?> loadTarballClassifications() => _loadData(_tarballClassificationsTable, 'classification');

  Future<void> saveDepartments(List<Map<String, dynamic>> data) => _saveData(_departmentsTable, 'department', data);
  Future<List<Map<String, dynamic>>?> loadDepartments() => _loadData(_departmentsTable, 'department');

  Future<void> saveCompanies(List<Map<String, dynamic>> data) => _saveData(_companiesTable, 'company', data);
  Future<List<Map<String, dynamic>>?> loadCompanies() => _loadData(_companiesTable, 'company');

  Future<void> savePositions(List<Map<String, dynamic>> data) => _saveData(_positionsTable, 'position', data);
  Future<List<Map<String, dynamic>>?> loadPositions() => _loadData(_positionsTable, 'position');

  Future<void> saveAirManualStations(List<Map<String, dynamic>> stations) => _saveData(_airManualStationsTable, 'station', stations);
  Future<List<Map<String, dynamic>>?> loadAirManualStations() => _loadData(_airManualStationsTable, 'station');

  Future<void> saveAirClients(List<Map<String, dynamic>> clients) => _saveData(_airClientsTable, 'client', clients);
  Future<List<Map<String, dynamic>>?> loadAirClients() => _loadData(_airClientsTable, 'client');

  Future<void> saveStates(List<Map<String, dynamic>> states) => _saveData(_statesTable, 'state', states);
  Future<List<Map<String, dynamic>>?> loadStates() => _loadData(_statesTable, 'state');
}