import 'dart:convert';

import '../utils/app_time.dart';

class TaskActivityLog {
  TaskActivityLog({
    required this.id,
    required this.taskId,
    this.actorId,
    required this.actionType,
    this.meta,
    required this.createdAt,
  });

  final String id;
  final String taskId;
  final String? actorId;
  final String actionType; // created, assigned, reassigned, started, completed
  final Map<String, dynamic>? meta;
  final DateTime createdAt;

  factory TaskActivityLog.fromMap(Map<String, dynamic> map) {
    // id and task_id may be returned as int or String depending on DB
    final rawId = map['id'];
    final rawTaskId = map['task_id'];

    String id = rawId == null ? '' : rawId.toString();
    String taskId = rawTaskId == null ? '' : rawTaskId.toString();

    // actor_id is nullable
    final actorId = map['actor_id']?.toString();

    // action_type fallback
    final actionType = (map['action_type'] as String?) ?? 'unknown';

    // meta may be a Map, Map<dynamic,dynamic>, JSON-encoded string, List, or null
    Map<String, dynamic>? meta;
    final rawMeta = map['meta'];
    if (rawMeta is Map<String, dynamic>) {
      meta = rawMeta;
    } else if (rawMeta is Map) {
      // convert dynamic-key map to Map<String, dynamic>
      try {
        meta = rawMeta.map((k, v) => MapEntry(k.toString(), v));
      } catch (_) {
        meta = null;
      }
    } else if (rawMeta is String && rawMeta.isNotEmpty) {
      try {
        final decoded = jsonDecode(rawMeta);
        if (decoded is Map<String, dynamic>) {
          meta = decoded;
        } else if (decoded is Map) {
          meta = decoded.map((k, v) => MapEntry(k.toString(), v));
        }
      } catch (_) {
        meta = null;
      }
    } else {
      meta = null;
    }

    // created_at may be ISO string, DateTime, or numeric (seconds/millis since epoch)
    final rawCreated = map['created_at'];
    DateTime createdAt;
    if (rawCreated is DateTime) {
      createdAt = AppTime.toAppTime(rawCreated);
    } else if (rawCreated is String) {
      try {
        createdAt = AppTime.parse(rawCreated);
      } catch (_) {
        createdAt = AppTime.now();
      }
    } else if (rawCreated is int) {
      // assume seconds or milliseconds
      if (rawCreated > 1e12) {
        // likely microseconds or nanoseconds - treat as milliseconds
        createdAt = AppTime.toAppTime(
          DateTime.fromMillisecondsSinceEpoch(rawCreated),
        );
      } else if (rawCreated > 1e10) {
        createdAt = AppTime.toAppTime(
          DateTime.fromMillisecondsSinceEpoch(rawCreated),
        );
      } else {
        createdAt = AppTime.toAppTime(
          DateTime.fromMillisecondsSinceEpoch(rawCreated * 1000),
        );
      }
    } else if (rawCreated is double) {
      final asInt = rawCreated.toInt();
      createdAt = AppTime.toAppTime(DateTime.fromMillisecondsSinceEpoch(asInt));
    } else {
      createdAt = AppTime.now();
    }

    return TaskActivityLog(
      id: id,
      taskId: taskId,
      actorId: actorId,
      actionType: actionType,
      meta: meta,
      createdAt: createdAt,
    );
  }
}
