import 'package:superport_v2/features/approvals/domain/entities/approval.dart';

/// 재고 트랜잭션 생성 입력 모델.
class StockTransactionCreateInput {
  StockTransactionCreateInput({
    required this.transactionTypeId,
    required this.transactionStatusId,
    required this.warehouseId,
    required this.transactionDate,
    required this.createdById,
    this.note,
    this.expectedReturnDate,
    this.lines = const [],
    this.customers = const [],
    required this.approval,
  });

  final int transactionTypeId;
  final int transactionStatusId;
  final int warehouseId;
  final DateTime transactionDate;
  final int createdById;
  final String? note;
  final DateTime? expectedReturnDate;
  final List<TransactionLineCreateInput> lines;
  final List<TransactionCustomerCreateInput> customers;
  final StockTransactionApprovalInput approval;

  Map<String, dynamic> toPayload() {
    final sanitizedNote = note?.trim();
    final linePayloads = lines
        .map((line) => line.toJson())
        .toList(growable: false);
    final customerPayloads = customers
        .map((customer) => customer.toJson())
        .toList(growable: false);
    return {
      'transaction_type_id': transactionTypeId,
      'transaction_status_id': transactionStatusId,
      'warehouse_id': warehouseId,
      'transaction_date': _formatNaiveDate(transactionDate),
      'created_by_id': createdById,
      'note': sanitizedNote,
      if (expectedReturnDate != null)
        'expected_return_date': _formatNaiveDate(expectedReturnDate!),
      'lines': linePayloads,
      'customers': customerPayloads,
      'approval': approval.toJson(),
    };
  }
}

/// 재고 트랜잭션 수정 입력 모델.
class StockTransactionUpdateInput {
  StockTransactionUpdateInput({
    required this.transactionStatusId,
    this.note,
    this.expectedReturnDate,
  });

  final int transactionStatusId;
  final String? note;
  final DateTime? expectedReturnDate;

  Map<String, dynamic> toPayload() {
    final sanitizedNote = note?.trim();
    return {
      'transaction_status_id': transactionStatusId,
      'note': sanitizedNote,
      'expected_return_date': expectedReturnDate == null
          ? null
          : _formatNaiveDate(expectedReturnDate!),
    };
  }
}

/// 재고 트랜잭션 라인 추가 입력 모델.
class TransactionLineCreateInput {
  TransactionLineCreateInput({
    required this.lineNo,
    required this.productId,
    required this.quantity,
    required this.unitPrice,
    this.note,
  });

  final int lineNo;
  final int productId;
  final int quantity;
  final double unitPrice;
  final String? note;

  Map<String, dynamic> toJson() {
    final sanitizedNote = note?.trim();
    return {
      'line_no': lineNo,
      'product_id': productId,
      'quantity': quantity,
      'unit_price': unitPrice,
      'note': sanitizedNote,
    };
  }
}

/// 재고 트랜잭션 라인 수정 입력 모델.
class TransactionLineUpdateInput {
  TransactionLineUpdateInput({
    required this.id,
    this.lineNo,
    this.quantity,
    this.unitPrice,
    this.note,
  });

  final int id;
  final int? lineNo;
  final int? quantity;
  final double? unitPrice;
  final String? note;

  Map<String, dynamic> toJson() {
    final sanitizedNote = note?.trim();
    return {
      'id': id,
      if (lineNo != null) 'line_no': lineNo,
      if (quantity != null) 'quantity': quantity,
      if (unitPrice != null) 'unit_price': unitPrice,
      if (note != null) 'note': sanitizedNote,
    };
  }
}

/// 재고 트랜잭션 고객 연결 추가 입력 모델.
class TransactionCustomerCreateInput {
  TransactionCustomerCreateInput({required this.customerId, this.note});

  final int customerId;
  final String? note;

  Map<String, dynamic> toJson() {
    final sanitizedNote = note?.trim();
    return {'customer_id': customerId, 'note': sanitizedNote};
  }
}

/// 재고 트랜잭션 고객 연결 수정 입력 모델.
class TransactionCustomerUpdateInput {
  TransactionCustomerUpdateInput({required this.id, this.note});

  final int id;
  final String? note;

  Map<String, dynamic> toJson() {
    final sanitizedNote = note?.trim();
    return {'id': id, 'note': sanitizedNote};
  }
}

/// 재고 트랜잭션 목록 조회 필터 모델.
class StockTransactionListFilter {
  StockTransactionListFilter({
    this.page = 1,
    this.pageSize = 20,
    this.query,
    this.transactionTypeId,
    this.transactionStatusId,
    this.warehouseId,
    this.customerId,
    this.from,
    this.to,
    this.sort,
    this.order,
    this.include = const ['lines', 'customers', 'approval'],
  });

  final int page;
  final int pageSize;
  final String? query;
  final int? transactionTypeId;
  final int? transactionStatusId;
  final int? warehouseId;
  final int? customerId;
  final DateTime? from;
  final DateTime? to;
  final String? sort;
  final String? order;
  final List<String> include;

  Map<String, dynamic> toQuery() {
    return {
      'page': page,
      'page_size': pageSize,
      if (query != null && query!.trim().isNotEmpty) 'q': query,
      if (transactionTypeId != null) 'transaction_type_id': transactionTypeId,
      if (transactionStatusId != null)
        'transaction_status_id': transactionStatusId,
      if (warehouseId != null) 'warehouse_id': warehouseId,
      if (customerId != null) 'customer_id': customerId,
      if (from != null) 'date_from': _formatDate(from!),
      if (to != null) 'date_to': _formatDate(to!),
      if (sort != null && sort!.trim().isNotEmpty) 'sort': sort,
      if (order != null && order!.trim().isNotEmpty) 'order': order,
      if (include.isNotEmpty) 'include': include.join(','),
    };
  }

  /// 백엔드가 요구하는 `yyyy-MM-dd`(NaiveDate) 형식으로 변환한다.
  String _formatDate(DateTime value) {
    return _formatNaiveDate(value);
  }
}

/// 재고 트랜잭션 생성 시 결재(Approval) 정보를 담는 입력 모델.
class StockTransactionApprovalInput {
  StockTransactionApprovalInput({
    required this.requestedById,
    this.approvalStatusId,
    this.templateId,
    this.finalApproverId,
    this.requestedAt,
    this.decidedAt,
    this.cancelledAt,
    this.lastActionAt,
    this.title,
    this.summary,
    this.note,
    this.metadata,
    this.steps = const [],
  });

  final int requestedById;
  final int? approvalStatusId;
  final int? templateId;
  final int? finalApproverId;
  final DateTime? requestedAt;
  final DateTime? decidedAt;
  final DateTime? cancelledAt;
  final DateTime? lastActionAt;
  final String? title;
  final String? summary;
  final String? note;
  final Map<String, dynamic>? metadata;
  final List<ApprovalStepAssignmentItem> steps;

  Map<String, dynamic> toJson() {
    final trimmedNote = note?.trim();
    final trimmedTitle = title?.trim();
    final trimmedSummary = summary?.trim();
    final payload = <String, dynamic>{
      'requested_by_id': requestedById,
      if (approvalStatusId != null) 'approval_status_id': approvalStatusId,
      if (templateId != null) 'template_id': templateId,
      if (finalApproverId != null) 'final_approver_id': finalApproverId,
      if (requestedAt != null) 'requested_at': _formatIsoUtc(requestedAt!),
      if (decidedAt != null) 'decided_at': _formatIsoUtc(decidedAt!),
      if (cancelledAt != null) 'cancelled_at': _formatIsoUtc(cancelledAt!),
      if (lastActionAt != null) 'last_action_at': _formatIsoUtc(lastActionAt!),
      if (trimmedTitle != null && trimmedTitle.isNotEmpty)
        'title': trimmedTitle,
      if (trimmedSummary != null && trimmedSummary.isNotEmpty)
        'summary': trimmedSummary,
      if (trimmedNote != null && trimmedNote.isNotEmpty) 'note': trimmedNote,
      if (metadata != null && metadata!.isNotEmpty) 'metadata': metadata,
    };
    if (steps.isNotEmpty) {
      payload['steps'] = steps
          .map((item) => _mapApprovalStep(item))
          .toList(growable: false);
    }
    return payload;
  }
}

String _formatNaiveDate(DateTime value) {
  final year = value.year.toString().padLeft(4, '0');
  final month = value.month.toString().padLeft(2, '0');
  final day = value.day.toString().padLeft(2, '0');
  return '$year-$month-$day';
}

String _formatIsoUtc(DateTime value) => value.toUtc().toIso8601String();

Map<String, dynamic> _mapApprovalStep(ApprovalStepAssignmentItem item) {
  final trimmedNote = item.note?.trim();
  return {
    'step_order': item.stepOrder,
    'approver_id': item.approverId,
    if (trimmedNote != null && trimmedNote.isNotEmpty) 'note': trimmedNote,
  };
}
