import '../domain/parsed_receipt_item.dart';
import 'dart:convert';
import 'dart:typed_data';

import 'package:http/http.dart' as http;
import 'dart:developer' as developer;

import '../../../core/api/api_exception.dart';
import '../domain/quick_import_result.dart';

/// Handles communication with the quick-import API endpoint.
///
/// Two modes:
///   • [importFile] — multipart upload (PDF / image bytes, max 10 MB).
///   • [importUrl]  — JSON body with `{ input: url }`.
class ImportRepository {
  final http.Client _client;
  final String _baseUrl;

  ImportRepository({http.Client? client})
      : _client = client ?? http.Client(),
        _baseUrl = const String.fromEnvironment(
          'API_BASE_URL',
          defaultValue: '/api',
        );

  /// Upload a receipt file for parsing (Fas 6b).
  /// Returns a list of parsed receipt items.
  Future<List<ParsedReceiptItem>> importReceiptFile({
    required Uint8List bytes,
    required String filename,
    String? token,
  }) async {
    try {
      developer.log('Starting receipt import for file: $filename', name: 'ImportRepository');
      
      final uri = Uri.parse('$_baseUrl/receipt-import');
      final request = http.MultipartRequest('POST', uri);
      
      if (token != null) {
        request.headers['Authorization'] = 'Bearer $token';
      }
      
      request.files.add(
        http.MultipartFile.fromBytes('file', bytes, filename: filename),
      );
      
      developer.log('Sending request to: ${request.url}', name: 'ImportRepository');
      
      final streamed = await _client.send(request).timeout(
        const Duration(seconds: 120),
        onTimeout: () {
          developer.log('Request timed out', name: 'ImportRepository', error: 'Timeout');
          throw ApiException(
            type: ApiErrorType.network,
            message: 'Importen tog för lång tid. Försök igen.',
          );
        },
      );
      
      final response = await http.Response.fromStream(streamed);
      developer.log('Received response with status: ${response.statusCode}', name: 'ImportRepository');
      
      if (response.statusCode < 200 || response.statusCode >= 300) {
        developer.log('Error response: ${response.body}', name: 'ImportRepository', error: 'HTTP Error');
        throw ApiException(
          type: _mapStatusCodeToErrorType(response.statusCode),
          message: 'Fel vid import: ${response.body}',
          statusCode: response.statusCode,
        );
      }
      
      final parsed = _parseResponse(response);
      developer.log('Response parsed, keys: ${parsed is Map ? parsed.keys.toList() : "list[${(parsed as List?)?.length}]"}', name: 'ImportRepository');

      // Backend returns ParsedReceiptItem[] directly as a JSON array
      if (parsed is List) {
        final items = parsed.map((e) => ParsedReceiptItem.fromJson(e as Map<String, dynamic>)).toList();
        developer.log('Successfully parsed ${items.length} items from array', name: 'ImportRepository');
        return items;
      }

      if (parsed is Map<String, dynamic>) {
        // Wrapped format: { items: [...] }
        if (parsed.containsKey('items')) {
          final items = (parsed['items'] as List?)?.map((e) => ParsedReceiptItem.fromJson(e as Map<String, dynamic>)).toList();
          if (items != null) {
            developer.log('Successfully parsed ${items.length} items', name: 'ImportRepository');
            return items;
          }
        }
        // Markdown-based receipt fallback — parse lines into items
        if (parsed.containsKey('markdown')) {
          developer.log('Got markdown receipt, parsing lines into items', name: 'ImportRepository');
          final lines = (parsed['markdown'] as String).split('\n');
          final items = lines
              .where((l) => l.trim().isNotEmpty && !l.startsWith('#') && !l.startsWith('=') && !l.startsWith('-'))
              .map((l) => ParsedReceiptItem(rawName: l.trim()))
              .toList();
          developer.log('Extracted ${items.length} lines as items', name: 'ImportRepository');
          return items;
        }
      }

      developer.log('Invalid response format: ${response.body}', name: 'ImportRepository', error: 'Invalid Data');
      throw ApiException(type: ApiErrorType.unknown, message: 'Felaktigt svar från servern.');
    } catch (e) {
      developer.log('Exception during receipt import: $e', name: 'ImportRepository', error: e);
      rethrow;
    }
  }

  /// Upload a file (PDF or image) for recipe extraction.
  ///
  /// [bytes] — raw file bytes from file_picker.
  /// [filename] — original filename (used for MIME detection on the server).
  /// [token] — JWT bearer token.
  Future<QuickImportResult> importFile({
    required Uint8List bytes,
    required String filename,
    String? token,
  }) async {
    try {
      developer.log('Starting file import for file: $filename', name: 'ImportRepository');
      
      final uri = Uri.parse('$_baseUrl/quick-import');
      final request = http.MultipartRequest('POST', uri);
      
      if (token != null) {
        request.headers['Authorization'] = 'Bearer $token';
      }
      
      request.files.add(
        http.MultipartFile.fromBytes('file', bytes, filename: filename),
      );
      
      developer.log('Sending request to: ${request.url}', name: 'ImportRepository');
      
      final streamed = await _client.send(request).timeout(
        const Duration(seconds: 120),
        onTimeout: () {
          developer.log('Request timed out', name: 'ImportRepository', error: 'Timeout');
          throw ApiException(
            type: ApiErrorType.network,
            message: 'Importen tog för lång tid. Försök igen.',
          );
        },
      );
      
      final response = await http.Response.fromStream(streamed);
      developer.log('Received response with status: ${response.statusCode}', name: 'ImportRepository');
      
      if (response.statusCode != 200) {
        developer.log('Error response: ${response.body}', name: 'ImportRepository', error: 'HTTP Error');
        throw ApiException(
          type: _mapStatusCodeToErrorType(response.statusCode),
          message: 'Fel vid import: ${response.body}',
          statusCode: response.statusCode,
        );
      }
      
      developer.log('Successfully imported file', name: 'ImportRepository');
      return QuickImportResult.fromJson(_parseResponse(response));
    } catch (e) {
      developer.log('Exception during file import: $e', name: 'ImportRepository', error: e);
      rethrow;
    }
  }

  /// Import a recipe from a URL.
  Future<QuickImportResult> importUrl({
    required String url,
    String? token,
  }) async {
    try {
      developer.log('Starting URL import for: $url', name: 'ImportRepository');
      
      final uri = Uri.parse('$_baseUrl/quick-import');
      final response = await _client
          .post(
            uri,
            headers: {
              'Content-Type': 'application/json',
              if (token != null) 'Authorization': 'Bearer $token',
            },
            body: jsonEncode({'input': url}),
          )
          .timeout(
            const Duration(seconds: 120),
            onTimeout: () {
              developer.log('Request timed out', name: 'ImportRepository', error: 'Timeout');
              throw ApiException(
                type: ApiErrorType.network,
                message: 'Importen tog för lång tid. Försök igen.',
              );
            },
          );
      
      developer.log('Received response with status: ${response.statusCode}', name: 'ImportRepository');
      
      if (response.statusCode != 200) {
        developer.log('Error response: ${response.body}', name: 'ImportRepository', error: 'HTTP Error');
        throw ApiException(
          type: _mapStatusCodeToErrorType(response.statusCode),
          message: 'Fel vid import: ${response.body}',
          statusCode: response.statusCode,
        );
      }
      
      developer.log('Successfully imported URL', name: 'ImportRepository');
      return QuickImportResult.fromJson(_parseResponse(response));
    } catch (e) {
      developer.log('Exception during URL import: $e', name: 'ImportRepository', error: e);
      rethrow;
    }
  }

  /// Helper method to map HTTP status codes to [ApiErrorType].
  ApiErrorType _mapStatusCodeToErrorType(int statusCode) {
    if (statusCode == 401) return ApiErrorType.unauthorized;
    if (statusCode == 403) return ApiErrorType.forbidden;
    if (statusCode >= 500) return ApiErrorType.server;
    return ApiErrorType.unknown;
  }

  /// Parse the HTTP response and handle potential errors.
  dynamic _parseResponse(http.Response response) {
    try {
      return jsonDecode(response.body);
    } catch (e) {
      developer.log('Failed to parse response: ${response.body}', name: 'ImportRepository', error: e);
      throw ApiException(
        type: ApiErrorType.unknown,
        message: 'Felaktigt svar från servern: ${response.body}',
      );
    }
  }
}
