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

import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart'; // For cache storage

import 'sheet.dart';

class ApiClient {
  final log = Logger("ApiClient");
  final String baseUrl;
  String? token;

  ApiClient({required this.baseUrl, this.token});

  Future<bool> login(String username, String password) async {
    log.info("Logging in...");
    try {
      final url = '$baseUrl/login';
      final response = await http.post(
        Uri.parse(url),
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({'email': username, 'password': password}),
      );

      if (response.statusCode == 200) {
        token = jsonDecode(response.body);
        log.info('Login successful');
        return true;
      } else {
        log.warning('Login failed: ${response.statusCode}, ${response.body}');
      }
    } catch (e) {
      log.warning('Error during login', e);
    }
    return false;
  }

  void logout() {
    token = null;
    log.info('Logged out successfully.');
  }

  Future<http.Response?> get(String endpoint, {bool isBinary = false}) async {
    try {
      final url = '$baseUrl$endpoint';
      final headers = {
        'Authorization': 'Bearer $token',
        if (!isBinary) 'Content-Type': 'application/json',
      };

      final response = await http.get(Uri.parse(url), headers: headers);

      if (response.statusCode == 200) {
        return response;
      } else {
        log.warning(
          'GET request failed: ${response.statusCode} ${response.body}',
        );
      }
    } catch (e) {
      log.warning('Error during GET request', e);
    }
    return null;
  }

  Future<http.Response?> post(
    String endpoint,
    Map<String, dynamic> body,
  ) async {
    try {
      final url = '$baseUrl$endpoint';
      final headers = {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/json',
      };

      final response = await http.post(
        Uri.parse(url),
        headers: headers,
        body: jsonEncode(body),
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        return response;
      } else {
        log.info(
          'POST request failed: ${response.statusCode} ${response.body}',
        );
      }
    } catch (e) {
      log.info('Error during POST request: $e');
    }
    return null;
  }

  Future<http.Response?> postFormData(String endpoint, String body) async {
    try {
      final url = '$baseUrl$endpoint';
      final headers = {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/x-www-form-urlencoded',
      };

      final response = await http.post(
        Uri.parse(url),
        headers: headers,
        body: body,
      );

      if (response.statusCode == 200 || response.statusCode == 201) {
        return response;
      } else {
        log.info(
          'POST Form Data request failed: ${response.statusCode} ${response.body}',
        );
      }
    } catch (e) {
      log.info('Error during POST Form Data request: $e');
    }
    return null;
  }

  Future<List<Sheet>> fetchSheets() async {
    try {
      final response = await get("/list/sheets");

      if (response == null) {
        return List.empty();
      }

      if (response.statusCode == 200) {
        final data = jsonDecode(response.body);
        return (data as List<dynamic>)
            .map((sheet) => Sheet.fromJson(sheet as Map<String, dynamic>))
            .toList();
      } else {
        log.warning(
          'Failed to fetch sheets with status: ${response.statusCode}',
        );
        log.info('Response: ${response.body}');
      }
    } catch (e) {
      log.warning('Error during fetching sheets', e);
    }

    return List.empty();
  }

  Future<Uint8List?> fetchPdfFileData(String sheetUuid) async {
    try {
      final response = await get('/sheet/pdf/$sheetUuid', isBinary: true);

      if (response != null && response.statusCode == 200) {
        log.info("PDF downloaded");
        return response.bodyBytes;
      } else {
        log.warning(
          "Failed to fetch PDF from API. Status: ${response?.statusCode}",
        );
      }
    } catch (e) {
      log.warning("Error fetching PDF", e);
    }

    return null;
  }

  Future<File?> getPdfFileCached(String sheetUuid) async {
    try {
      final cacheDir = await getTemporaryDirectory();
      final cachedPdfPath = '${cacheDir.path}/$sheetUuid.pdf';

      final cachedFile = File(cachedPdfPath);
      if (await cachedFile.exists()) {
        log.info("PDF found in cache: $cachedPdfPath");
        return cachedFile;
      }

      final pdfFileData = await fetchPdfFileData(sheetUuid);
      await cachedFile.writeAsBytes(
        pdfFileData!,
      ); // TODO: proper error handling
      log.info("PDF cached at: $cachedPdfPath");
      return cachedFile;
    } catch (e) {
      log.warning("Error fetching PDF", e);
    }

    return null;
  }
}
