// Import all task types
import 'tasks/generic_task.dart';
import 'tasks/confirmation_task.dart';
import 'tasks/photo_task.dart';
import 'tasks/todolist_task.dart';
import 'tasks/signature_task.dart';
import 'tasks/barcode_task.dart';
import 'tasks/comment_task.dart';

abstract class Task {
  final String id;
  final String jobId;
  final int? stationOrder;
  final bool completed;
  final bool optional;
  final DateTime? completedAt;
  final String? completedBy;
  final int? taskOrder;
  final String? title;
  final String? description;
  final String? displayName;

  Task({
    required this.id,
    required this.jobId,
    this.stationOrder,
    this.completed = false,
    this.optional = false,
    this.completedAt,
    this.completedBy,
    this.taskOrder,
    this.title,
    this.description,
    this.displayName,
  });

  factory Task.fromJson(Map<String, dynamic> json) {
    // Get task specific data to determine task type
    final taskSpecificData = json['taskSpecificData'] as Map<String, dynamic>?;
    final taskType =
        (taskSpecificData?['taskType'] ?? json['taskType'])?.toString();

    // Create specific task type based on taskType
    switch (taskType) {
      case 'CONFIRMATION':
        return ConfirmationTask.fromJson(json);
      case 'PHOTO':
        return PhotoTask.fromJson(json);
      case 'TODOLIST':
        return TodoListTask.fromJson(json);
      case 'SIGNATURE':
        return SignatureTask.fromJson(json);
      case 'BARCODE':
        return BarcodeTask.fromJson(json);
      case 'COMMENT':
        return CommentTask.fromJson(json);
      case 'GENERIC':
        return GenericTask.fromJson(json);
      default:
        // Fallback to a generic task if no specific type is found
        return GenericTask.fromJson(json);
    }
  }

  Map<String, dynamic> toJson();

  Task copyWith({
    String? id,
    String? jobId,
    int? stationOrder,
    bool? completed,
    bool? optional,
    DateTime? completedAt,
    String? completedBy,
    int? taskOrder,
    String? title,
    String? description,
    String? displayName,
  });

  @override
  String toString() {
    return 'Task(id: $id, jobId: $jobId, stationOrder: $stationOrder, completed: $completed, taskOrder: $taskOrder)';
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is Task && other.id == id;
  }

  @override
  int get hashCode => id.hashCode;

  /// Parse DateTime from either string or array format
  static DateTime? _parseDateTime(dynamic value) {
    if (value == null) return null;

    if (value is String) {
      return DateTime.tryParse(value);
    }

    if (value is List && value.isNotEmpty) {
      try {
        // Array format: [year, month, day, hour, minute, second, microsecond]
        final year = value[0] as int;
        final month = value.length > 1 ? value[1] as int : 1;
        final day = value.length > 2 ? value[2] as int : 1;
        final hour = value.length > 3 ? value[3] as int : 0;
        final minute = value.length > 4 ? value[4] as int : 0;
        final second = value.length > 5 ? value[5] as int : 0;
        final microsecond = value.length > 6 ? value[6] as int : 0;

        return DateTime(year, month, day, hour, minute, second, microsecond);
      } catch (e) {
        return null;
      }
    }

    return null;
  }

  static String? _readOptionalString(dynamic value) {
    if (value == null) {
      return null;
    }
    if (value is String) {
      return value;
    }
    if (value is num || value is bool) {
      return value.toString();
    }
    return null;
  }

  static int? _readOptionalInt(dynamic value) {
    if (value is int) {
      return value;
    }
    if (value is num) {
      return value.toInt();
    }
    if (value is String) {
      return int.tryParse(value);
    }
    return null;
  }

  // Helper method to parse common properties
  static Map<String, dynamic> parseCommonProperties(Map<String, dynamic> json) {
    // Parse the complex id object - can be either a Map or a simple string
    String idValue = '';
    if (json['id'] is Map) {
      final idMap = json['id'] as Map<String, dynamic>;
      idValue = idMap['timestamp']?.toString() ?? '';
    } else {
      idValue = json['id']?.toString() ?? '';
    }

    // Parse the complex jobId object - can be either a Map or a simple string
    String jobIdValue = '';
    if (json['jobId'] is Map) {
      final jobIdMap = json['jobId'] as Map<String, dynamic>;
      jobIdValue = jobIdMap['timestamp']?.toString() ?? '';
    } else {
      jobIdValue = json['jobId']?.toString() ?? '';
    }

    // Parse completedAt using the helper method to handle both string and array formats
    final completedAt = _parseDateTime(json['completedAt']);

    final taskSpecificData = json['taskSpecificData'] as Map<String, dynamic>?;
    final stationOrder = _readOptionalInt(json['stationOrder']);
    final title = _readOptionalString(
      json['title'] ?? taskSpecificData?['title'],
    );
    final description = _readOptionalString(
      json['description'] ?? taskSpecificData?['description'],
    );
    final displayName = _readOptionalString(
      json['displayName'] ?? taskSpecificData?['displayName'],
    );

    return {
      'id': idValue,
      'jobId': jobIdValue,
      'stationOrder': stationOrder,
      'completed': json['completed'] ?? false,
      'optional': json['optional'] ?? false,
      'completedAt': completedAt,
      'completedBy': json['completedBy'],
      'taskOrder': json['taskOrder'],
      'title': title,
      'description': description,
      'displayName': displayName,
    };
  }
}
