import 'dart:typed_data';
import 'dart:convert';
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../domain/parsed_receipt_item.dart';

// ── Destination-enum ──────────────────────────────────────────────────────────

enum ImportDestination { inventory, pantry }

enum CategorySelectionSource { ai, manual }

// ── Per-rad redigeringstillstånd ──────────────────────────────────────────────

class ItemEdit {
  final int? productId;
  final String? productName;
  final bool learnAlias;
  final bool learnAliasGlobally;
  final int? categoryId;
  final String? categoryPath;
  final CategorySelectionSource? categorySource;
  final double? quantity;
  final String? unit;
  final double? packQuantity;
  final String? packUnit;
  final double? packageCount;
  final ImportDestination destination;

  const ItemEdit({
    this.productId,
    this.productName,
    this.learnAlias = false,
    this.learnAliasGlobally = false,
    this.categoryId,
    this.categoryPath,
    this.categorySource,
    this.quantity,
    this.unit,
    this.packQuantity,
    this.packUnit,
    this.packageCount,
    this.destination = ImportDestination.inventory,
  });
}

// ── Session-state ─────────────────────────────────────────────────────────────

class ReceiptImportSession {
  final Uint8List? fileBytes;
  final String? fileExtension;
  final String? fileName;
  final List<ParsedReceiptItem>? items; // null = ej parsad än
  final Map<int, ItemEdit> edits;
  final Map<int, bool> selected;

  const ReceiptImportSession({
    this.fileBytes,
    this.fileExtension,
    this.fileName,
    this.items,
    this.edits = const {},
    this.selected = const {},
  });

  ReceiptImportSession copyWith({
    Uint8List? fileBytes,
    String? fileExtension,
    String? fileName,
    List<ParsedReceiptItem>? items,
    Map<int, ItemEdit>? edits,
    Map<int, bool>? selected,
  }) =>
      ReceiptImportSession(
        fileBytes: fileBytes ?? this.fileBytes,
        fileExtension: fileExtension ?? this.fileExtension,
        fileName: fileName ?? this.fileName,
        items: items ?? this.items,
        edits: edits ?? this.edits,
        selected: selected ?? this.selected,
      );

  Map<String, dynamic> toJson() => {
    'fileBytes': fileBytes == null ? null : base64Encode(fileBytes!),
    'fileExtension': fileExtension,
    'fileName': fileName,
    'items': items?.map((e) => e.toJson()).toList(),
    'edits': edits.map((key, value) => MapEntry(key.toString(), {
      'productId': value.productId,
      'productName': value.productName,
      'learnAlias': value.learnAlias,
      'learnAliasGlobally': value.learnAliasGlobally,
      'categoryId': value.categoryId,
      'categoryPath': value.categoryPath,
      'categorySource': value.categorySource?.name,
      'quantity': value.quantity,
      'unit': value.unit,
      'packQuantity': value.packQuantity,
      'packUnit': value.packUnit,
      'packageCount': value.packageCount,
      'destination': value.destination.name,
    })),
    'selected': selected.map((key, value) => MapEntry(key.toString(), value)),
  };

  factory ReceiptImportSession.fromJson(Map<String, dynamic> json) {
    final rawItems = json['items'] as List<dynamic>?;
    final items = rawItems
        ?.whereType<Map<String, dynamic>>()
        .map(ParsedReceiptItem.fromJson)
        .toList();

    final rawEdits = (json['edits'] as Map<String, dynamic>? ?? {});
    final edits = <int, ItemEdit>{};
    for (final entry in rawEdits.entries) {
      final idx = int.tryParse(entry.key);
      final value = entry.value;
      if (idx == null || value is! Map<String, dynamic>) continue;
      edits[idx] = ItemEdit(
        productId: (value['productId'] as num?)?.toInt(),
        productName: value['productName'] as String?,
        learnAlias: value['learnAlias'] == true,
        learnAliasGlobally: value['learnAliasGlobally'] == true,
        categoryId: (value['categoryId'] as num?)?.toInt(),
        categoryPath: value['categoryPath'] as String?,
        categorySource: switch (value['categorySource']) {
          'ai' => CategorySelectionSource.ai,
          'manual' => CategorySelectionSource.manual,
          _ => null,
        },
        quantity: (value['quantity'] as num?)?.toDouble(),
        unit: value['unit'] as String?,
        packQuantity: (value['packQuantity'] as num?)?.toDouble(),
        packUnit: value['packUnit'] as String?,
        packageCount: (value['packageCount'] as num?)?.toDouble(),
        destination: (value['destination'] as String?) == ImportDestination.pantry.name
            ? ImportDestination.pantry
            : ImportDestination.inventory,
      );
    }

    final rawSelected = (json['selected'] as Map<String, dynamic>? ?? {});
    final selected = <int, bool>{};
    for (final entry in rawSelected.entries) {
      final idx = int.tryParse(entry.key);
      if (idx == null) continue;
      selected[idx] = entry.value == true;
    }

    Uint8List? fileBytes;
    final fileBytesRaw = json['fileBytes'];
    if (fileBytesRaw is String && fileBytesRaw.isNotEmpty) {
      try {
        fileBytes = base64Decode(fileBytesRaw);
      } catch (_) {
        fileBytes = null;
      }
    }

    return ReceiptImportSession(
      fileBytes: fileBytes,
      fileExtension: json['fileExtension'] as String?,
      fileName: json['fileName'] as String?,
      items: items,
      edits: edits,
      selected: selected,
    );
  }
}

// ── Notifier ──────────────────────────────────────────────────────────────────

class ReceiptImportSessionNotifier
    extends Notifier<ReceiptImportSession?> {
  static const _storageKey = 'receipt_import_session_v1';

  @override
  ReceiptImportSession? build() => null;

  /// Ny fil vald — återställer items/edits/selected, behåller ingenting gammalt.
  void setFile(Uint8List bytes, String extension, {String? fileName}) {
    state = ReceiptImportSession(
      fileBytes: bytes,
      fileExtension: extension,
      fileName: fileName,
    );
    unawaited(_persist());
  }

  void setItems(List<ParsedReceiptItem> items) {
    // Bevara filinformationen när items sätts
    state = (state ?? const ReceiptImportSession()).copyWith(items: items);
    unawaited(_persist());
  }

  void setImportedResult({
    required List<ParsedReceiptItem> items,
    required Map<int, ItemEdit> edits,
    required Map<int, bool> selected,
  }) {
    final current = state ?? const ReceiptImportSession();
    state = current.copyWith(
      items: items,
      edits: edits,
      selected: selected,
    );
    unawaited(_persist());
  }

  void setEdit(int index, ItemEdit edit) {
    if (state == null) return;
    final edits = Map<int, ItemEdit>.from(state!.edits)..[index] = edit;
    state = state!.copyWith(edits: edits);
    unawaited(_persist());
  }

  void setSelected(int index, bool value) {
    if (state == null) return;
    final selected = Map<int, bool>.from(state!.selected)..[index] = value;
    state = state!.copyWith(selected: selected);
    unawaited(_persist());
  }

  void setSelectedForIndexes(Iterable<int> indexes, bool value) {
    if (state == null) return;
    final selected = Map<int, bool>.from(state!.selected);
    for (final index in indexes) {
      selected[index] = value;
    }
    state = state!.copyWith(selected: selected);
    unawaited(_persist());
  }

  void setSelectedForAll(int count, bool value) {
    if (state == null) return;
    final selected = <int, bool>{
      for (var i = 0; i < count; i++) i: value,
    };
    state = state!.copyWith(selected: selected);
    unawaited(_persist());
  }

  Future<void> restore() async {
    final prefs = await SharedPreferences.getInstance();
    final raw = prefs.getString(_storageKey);
    if (raw == null || raw.isEmpty) return;

    try {
      final decoded = jsonDecode(raw);
      if (decoded is Map<String, dynamic>) {
        state = ReceiptImportSession.fromJson(decoded);
      }
    } catch (_) {
      await prefs.remove(_storageKey);
    }
  }

  void clear() {
    state = null;
    unawaited(_removePersisted());
  }

  Future<void> _persist() async {
    final prefs = await SharedPreferences.getInstance();
    if (state == null) {
      await prefs.remove(_storageKey);
      return;
    }
    await prefs.setString(_storageKey, jsonEncode(state!.toJson()));
  }

  Future<void> _removePersisted() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_storageKey);
  }
}

final receiptImportSessionProvider =
    NotifierProvider<ReceiptImportSessionNotifier, ReceiptImportSession?>(
  ReceiptImportSessionNotifier.new,
);
