import 'dart:convert';
import 'package:intl/intl.dart';

/// Parse the entire response
ExpenseResponse expenseResponseFromJson(String str) =>
    ExpenseResponse.fromJson(json.decode(str));

String expenseResponseToJson(ExpenseResponse data) =>
    json.encode(data.toJson());

/// --- Top-level Response ---
class ExpenseResponse {
  final bool success;
  final String message;
  final ExpenseData data;
  final dynamic errors;
  final int? statusCode;
  final DateTime? timestamp;

  ExpenseResponse({
    required this.success,
    required this.message,
    required this.data,
    this.errors,
    this.statusCode,
    this.timestamp,
  });

  factory ExpenseResponse.fromJson(Map<String, dynamic> json) {
    final dataField = json["data"];
    return ExpenseResponse(
      success: json["success"] ?? false,
      message: json["message"] ?? '',
      data: (dataField is Map<String, dynamic>)
          ? ExpenseData.fromJson(dataField)
          : ExpenseData.empty(),
      errors: json["errors"],
      statusCode: json["statusCode"],
      timestamp: json["timestamp"] != null
          ? DateTime.tryParse(json["timestamp"])
          : null,
    );
  }

  Map<String, dynamic> toJson() => {
        "success": success,
        "message": message,
        "data": data.toJson(),
        "errors": errors,
        "statusCode": statusCode,
        "timestamp": timestamp?.toIso8601String(),
      };
}

/// --- Expense Data ---
class ExpenseData {
  final Filter? currentFilter;
  final int currentPage;
  final int totalPages;
  final int totalEntites;
  final List<ExpenseModel> data;

  ExpenseData({
    required this.currentFilter,
    required this.currentPage,
    required this.totalPages,
    required this.totalEntites,
    required this.data,
  });

  factory ExpenseData.fromJson(Map<String, dynamic> json) => ExpenseData(
        currentFilter: json["currentFilter"] != null
            ? Filter.fromJson(json["currentFilter"])
            : null,
        currentPage: json["currentPage"] ?? 0,
        totalPages: json["totalPages"] ?? 0,
        totalEntites: json["totalEntites"] ?? 0,
        data: (json["data"] as List<dynamic>? ?? [])
            .map((x) => ExpenseModel.fromJson(x))
            .toList(),
      );

  factory ExpenseData.empty() => ExpenseData(
        currentFilter: null,
        currentPage: 0,
        totalPages: 0,
        totalEntites: 0,
        data: [],
      );

  Map<String, dynamic> toJson() => {
        "currentFilter": currentFilter?.toJson(),
        "currentPage": currentPage,
        "totalPages": totalPages,
        "totalEntites": totalEntites,
        "data": List<dynamic>.from(data.map((x) => x.toJson())),
      };
}

/// --- Filter ---
class Filter {
  final List<String>? projectIds;
  final List<String>? statusIds;
  final List<String>? createdByIds;
  final List<String>? paidById;
  final List<String>? expenseCategoryIds;
  final bool? isTransactionDate;
  final DateTime? startDate;
  final DateTime? endDate;

  Filter({
    this.projectIds,
    this.statusIds,
    this.createdByIds,
    this.paidById,
    this.expenseCategoryIds,
    this.isTransactionDate,
    this.startDate,
    this.endDate,
  });

  factory Filter.fromJson(Map<String, dynamic> json) => Filter(
        projectIds: json["projectIds"] != null
            ? List<String>.from(json["projectIds"])
            : null,
        statusIds: json["statusIds"] != null
            ? List<String>.from(json["statusIds"])
            : null,
        createdByIds: json["createdByIds"] != null
            ? List<String>.from(json["createdByIds"])
            : null,
        paidById: json["paidById"] != null
            ? List<String>.from(json["paidById"])
            : null,
        expenseCategoryIds: json["expenseCategoryIds"] != null
            ? List<String>.from(json["expenseCategoryIds"])
            : null,
        isTransactionDate: json["isTransactionDate"],
        startDate: json["startDate"] != null
            ? DateTime.tryParse(json["startDate"])
            : null,
        endDate: json["endDate"] != null
            ? DateTime.tryParse(json["endDate"])
            : null,
      );

  Map<String, dynamic> toJson() => {
        "projectIds": projectIds,
        "statusIds": statusIds,
        "createdByIds": createdByIds,
        "paidById": paidById,
        "expenseCategoryIds": expenseCategoryIds,
        "isTransactionDate": isTransactionDate,
        "startDate": startDate?.toIso8601String(),
        "endDate": endDate?.toIso8601String(),
      };
}

/// --- Expense Model ---
class ExpenseModel {
  final String id;
  final Project project;
  final ExpenseType expenseCategory;
  final PaymentMode paymentMode;
  final PaidBy paidBy;
  final CreatedBy createdBy;
  final DateTime transactionDate;
  final DateTime createdAt;
  final String supplerName;
  final String expenseUId;
  final String? paymentRequestUID;
  final String transactionId;
  final double amount;
  final Currency currency;
  final String description;
  final double? baseAmount;
  final double? taxAmount;
  final Status status;
  final List<Status> nextStatus;
  final bool preApproved;

  ExpenseModel({
    required this.id,
    required this.project,
    required this.expenseCategory,
    required this.paymentMode,
    required this.paidBy,
    required this.createdBy,
    required this.transactionDate,
    required this.createdAt,
    required this.supplerName,
    required this.expenseUId,
    this.paymentRequestUID,
    required this.transactionId,
    required this.amount,
    required this.currency,
    required this.description,
    this.baseAmount,
    this.taxAmount,
    required this.status,
    required this.nextStatus,
    required this.preApproved,
  });

  String get formattedAmount {
    final formatter = NumberFormat.currency(
      locale: 'en_IN',
      symbol: '${currency.symbol} ',
      decimalDigits: 2,
    );
    return formatter.format(amount);
  }

  factory ExpenseModel.fromJson(Map<String, dynamic> json) => ExpenseModel(
        id: json["id"] ?? '',
        project: Project.fromJson(json["project"] ?? {}),
        expenseCategory: ExpenseType.fromJson(json["expenseCategory"] ?? {}),
        paymentMode: PaymentMode.fromJson(json["paymentMode"] ?? {}),
        paidBy: PaidBy.fromJson(json["paidBy"] ?? {}),
        createdBy: CreatedBy.fromJson(json["createdBy"] ?? {}),
        transactionDate:
            DateTime.tryParse(json["transactionDate"] ?? '') ?? DateTime.now(),
        createdAt:
            DateTime.tryParse(json["createdAt"] ?? '') ?? DateTime.now(),
        supplerName: json["supplerName"] ?? '',
        expenseUId: json["expenseUId"] ?? '',
        paymentRequestUID: json["paymentRequestUID"],
        transactionId: json["transactionId"] ?? '',
        amount: (json["amount"] ?? 0).toDouble(),
        currency: Currency.fromJson(json["currency"] ?? {}),
        description: json["description"] ?? '',
        baseAmount: json["baseAmount"] != null
            ? (json["baseAmount"] as num).toDouble()
            : null,
        taxAmount: json["taxAmount"] != null
            ? (json["taxAmount"] as num).toDouble()
            : null,
        status: Status.fromJson(json["status"] ?? {}),
        nextStatus: (json["nextStatus"] as List<dynamic>? ?? [])
            .map((x) => Status.fromJson(x))
            .toList(),
        preApproved: json["preApproved"] ?? false,
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "project": project.toJson(),
        "expenseCategory": expenseCategory.toJson(),
        "paymentMode": paymentMode.toJson(),
        "paidBy": paidBy.toJson(),
        "createdBy": createdBy.toJson(),
        "transactionDate": transactionDate.toIso8601String(),
        "createdAt": createdAt.toIso8601String(),
        "supplerName": supplerName,
        "expenseUId": expenseUId,
        "paymentRequestUID": paymentRequestUID,
        "transactionId": transactionId,
        "amount": amount,
        "currency": currency.toJson(),
        "description": description,
        "baseAmount": baseAmount,
        "taxAmount": taxAmount,
        "status": status.toJson(),
        "nextStatus": List<dynamic>.from(nextStatus.map((x) => x.toJson())),
        "preApproved": preApproved,
      };
}

/// --- Project ---
class Project {
  final String id;
  final String name;
  final String shortName;
  final String projectAddress;
  final String contactPerson;
  final DateTime startDate;
  final DateTime endDate;
  final String projectStatusId;

  Project({
    required this.id,
    required this.name,
    required this.shortName,
    required this.projectAddress,
    required this.contactPerson,
    required this.startDate,
    required this.endDate,
    required this.projectStatusId,
  });

  factory Project.fromJson(Map<String, dynamic> json) => Project(
        id: json["id"] ?? '',
        name: json["name"] ?? '',
        shortName: json["shortName"] ?? '',
        projectAddress: json["projectAddress"] ?? '',
        contactPerson: json["contactPerson"] ?? '',
        startDate:
            DateTime.tryParse(json["startDate"] ?? '') ?? DateTime.now(),
        endDate: DateTime.tryParse(json["endDate"] ?? '') ?? DateTime.now(),
        projectStatusId: json["projectStatusId"] ?? '',
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "shortName": shortName,
        "projectAddress": projectAddress,
        "contactPerson": contactPerson,
        "startDate": startDate.toIso8601String(),
        "endDate": endDate.toIso8601String(),
        "projectStatusId": projectStatusId,
      };
}

/// --- Expense Category ---
class ExpenseType {
  final String id;
  final String name;
  final bool noOfPersonsRequired;
  final String description;

  ExpenseType({
    required this.id,
    required this.name,
    required this.noOfPersonsRequired,
    required this.description,
  });

  factory ExpenseType.fromJson(Map<String, dynamic> json) => ExpenseType(
        id: json["id"] ?? '',
        name: json["name"] ?? '',
        noOfPersonsRequired: json["noOfPersonsRequired"] ?? false,
        description: json["description"] ?? '',
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "noOfPersonsRequired": noOfPersonsRequired,
        "description": description,
      };
}

/// --- Payment Mode ---
class PaymentMode {
  final String id;
  final String name;
  final String description;

  PaymentMode({
    required this.id,
    required this.name,
    required this.description,
  });

  factory PaymentMode.fromJson(Map<String, dynamic> json) => PaymentMode(
        id: json["id"] ?? '',
        name: json["name"] ?? '',
        description: json["description"] ?? '',
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "description": description,
      };
}

/// --- PaidBy & CreatedBy ---
class PaidBy {
  final String id;
  final String firstName;
  final String lastName;
  final String photo;
  final String jobRoleId;
  final String? jobRoleName;

  PaidBy({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.photo,
    required this.jobRoleId,
    this.jobRoleName,
  });

  factory PaidBy.fromJson(Map<String, dynamic> json) => PaidBy(
        id: json["id"] ?? '',
        firstName: json["firstName"] ?? '',
        lastName: json["lastName"] ?? '',
        photo: json["photo"] ?? '',
        jobRoleId: json["jobRoleId"] ?? '',
        jobRoleName: json["jobRoleName"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "firstName": firstName,
        "lastName": lastName,
        "photo": photo,
        "jobRoleId": jobRoleId,
        "jobRoleName": jobRoleName,
      };
}

class CreatedBy extends PaidBy {
  CreatedBy({
    required super.id,
    required super.firstName,
    required super.lastName,
    required super.photo,
    required super.jobRoleId,
    super.jobRoleName,
  });

  factory CreatedBy.fromJson(Map<String, dynamic> json) =>
      CreatedBy(
        id: json["id"] ?? '',
        firstName: json["firstName"] ?? '',
        lastName: json["lastName"] ?? '',
        photo: json["photo"] ?? '',
        jobRoleId: json["jobRoleId"] ?? '',
        jobRoleName: json["jobRoleName"],
      );
}

/// --- Status ---
class Status {
  final String id;
  final String name;
  final String displayName;
  final String description;
  final String color;
  final bool isSystem;

  Status({
    required this.id,
    required this.name,
    required this.displayName,
    required this.description,
    required this.color,
    required this.isSystem,
  });

  factory Status.fromJson(Map<String, dynamic> json) => Status(
        id: json["id"] ?? '',
        name: json["name"] ?? '',
        displayName: json["displayName"] ?? '',
        description: json["description"] ?? '',
        color: (json["color"] ?? '').replaceAll("'", ''),
        isSystem: json["isSystem"] ?? false,
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "displayName": displayName,
        "description": description,
        "color": color,
        "isSystem": isSystem,
      };
}

/// --- Currency ---
class Currency {
  final String id;
  final String currencyCode;
  final String currencyName;
  final String symbol;
  final bool isActive;

  Currency({
    required this.id,
    required this.currencyCode,
    required this.currencyName,
    required this.symbol,
    required this.isActive,
  });

  factory Currency.fromJson(Map<String, dynamic> json) => Currency(
        id: json["id"] ?? '',
        currencyCode: json["currencyCode"] ?? '',
        currencyName: json["currencyName"] ?? '',
        symbol: json["symbol"] ?? '',
        isActive: json["isActive"] ?? false,
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "currencyCode": currencyCode,
        "currencyName": currencyName,
        "symbol": symbol,
        "isActive": isActive,
      };
}
