import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/network/api_client.dart';
import '../../app.dart';
import '../../shared/models/pagination_model.dart';
import '../../core/data/api_cache.dart';
import '../../core/navigation/host_app_channel.dart';
import '../../shared/models/bill_attachment.dart';
import '../../shared/models/bill_file_rights.dart';
import 'expense_apply_model.dart';
import 'report_model.dart';

final expenseApplyApiProvider = Provider<ExpenseApplyApi>(
  (ref) => ExpenseApplyApi(ref.read(apiClientProvider)),
);

// ═══ 参考数据模型（API 返回） ═══

class CostTypeItem {
  final String typeNo;
  final String typeName;
  final String accNo;
  final String accName;
  const CostTypeItem({
    required this.typeNo,
    required this.typeName,
    required this.accNo,
    required this.accName,
  });
  factory CostTypeItem.fromJson(Map<String, dynamic> json) => CostTypeItem(
    typeNo: json['typeNo'] as String? ?? '',
    typeName: json['typeName'] as String? ?? '',
    accNo: json['accNo'] as String? ?? '',
    accName: json['accName'] as String? ?? '',
  );
}

class CostProjectItem {
  final String idx1;
  final String name;
  final String accNo;
  final String accName;
  const CostProjectItem({
    required this.idx1,
    required this.name,
    required this.accNo,
    required this.accName,
  });
  factory CostProjectItem.fromJson(Map<String, dynamic> json) =>
      CostProjectItem(
        idx1: json['idx1'] as String? ?? '',
        name: json['name'] as String? ?? '',
        accNo: json['accNo'] as String? ?? '',
        accName: json['accName'] as String? ?? '',
      );
}

class ProjectCodeItem {
  final String objNo;
  final String name;
  const ProjectCodeItem({required this.objNo, required this.name});
  factory ProjectCodeItem.fromJson(Map<String, dynamic> json) =>
      ProjectCodeItem(
        objNo: json['objNo'] as String? ?? '',
        name: json['name'] as String? ?? '',
      );
}

class DepartmentItem {
  final String dep;
  final String name;
  const DepartmentItem({required this.dep, required this.name});
  factory DepartmentItem.fromJson(Map<String, dynamic> json) => DepartmentItem(
    dep: json['dep'] as String? ?? '',
    name: json['name'] as String? ?? '',
  );
}

class ExpenseApplyApi {
  final ApiClient _client;
  final _cache = ApiCache(keyPrefix: '${HostAppChannel.sn}_${HostAppChannel.compNo}_${HostAppChannel.usr}');
  ExpenseApplyApi(this._client);

  /// 清除所有基础资料缓存（picker 下拉刷新时调用）。
  void clearRefCache() => _cache.clear();

  /// 费用申请列表（分页）
  Future<PaginatedData<ExpenseApplyModel>> fetchList({
    String status = '',
    String keyword = '',
    String startDate = '',
    String endDate = '',
    String usr = '',
    String sortDir = 'DESC',
    int page = 1,
    int size = 20,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseApplyList',
      queryParameters: {
        'status': status,
        'keyword': keyword,
        'startDate': startDate,
        'endDate': endDate,
        'usr': usr,
        'sortDir': sortDir,
        'page': page,
        'size': size,
      },
    );
    return PaginatedData.fromJson(response.data!, ExpenseApplyModel.fromJson);
  }

  /// 费用申请详情（主表+明细）
  Future<ExpenseApplyModel> fetchDetail(String billNo) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseApplyDetail',
      queryParameters: {'billNo': billNo},
    );
    return ExpenseApplyModel.fromJson(response.data!);
  }

  /// 费用类别字典
  Future<List<CostTypeItem>> getCostTypes({
    String keyword = '',
    String accNo = '',
    int page = 1,
    int size = 100,
  }) async {
    final cacheKey = 'getCostTypes_${keyword}_${accNo}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetCostTypes',
        queryParameters: {
          'keyword': keyword,
          'accNo': accNo,
          'page': page,
          'size': size,
        },
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => CostTypeItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 费用项目字典（分页）
  Future<List<CostProjectItem>> getCostProjects({
    String keyword = '',
    String accNo = '',
    bool onlyActive = true,
    int page = 1,
    int size = 20,
  }) async {
    final cacheKey = 'getCostProjects_${keyword}_${accNo}_${onlyActive}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetCostProjects',
        queryParameters: {
          'keyword': keyword,
          'accNo': accNo,
          'onlyActive': onlyActive,
          'page': page,
          'size': size,
        },
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => CostProjectItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 项目代号
  Future<List<ProjectCodeItem>> getProjectCodes({
    String keyword = '',
    String billDate = '',
    int page = 1,
    int size = 100,
  }) async {
    final cacheKey = 'getProjectCodes_${keyword}_${billDate}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetProjectCodes',
        queryParameters: {
          'keyword': keyword,
          'billDate': billDate,
          'page': page,
          'size': size,
        },
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => ProjectCodeItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 部门
  Future<List<DepartmentItem>> getDepartments({
    String keyword = '',
    bool onlyActive = true,
    int page = 1,
    int size = 100,
  }) async {
    final cacheKey = 'getDepartments_${keyword}_${onlyActive}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetDepartments',
        queryParameters: {
          'keyword': keyword,
          'onlyActive': onlyActive,
          'page': page,
          'size': size,
        },
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => DepartmentItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 会计科目树（级联选择器数据源）
  Future<dynamic> getAcctSubjects() async {
    final response = await _client.get('/OA/GetAcctSubjects');
    return response.data;
  }

  /// 提交审批，返回申请单号（提取失败时返回 null，不影响主流程）
  /// BillSave 返回格式: { callok:true, resultData:{ BIL_NO:"AE20267020005", ... } }
  Future<String?> submit(Map<String, dynamic> data) async {
    final response = await _client.post<Map<String, dynamic>>(
      '/OA/BillSave',
      data: {
        'erpCategory': 'MasterService',
        'billId': 'AE',
        'procId': '',
        'data': data,
      },
    );
    final resData = response.data;
    if (resData == null) return null;

    // 从 resultData 中取（BillSave 实际返回的嵌套格式）
    final resultData = resData['resultData'];
    if (resultData is Map<String, dynamic>) {
      // BIL_NO 是 BillSave 返回的通用单号字段（不区分 AE/BX）
      final bilNo = resultData['BIL_NO'] as String?;
      if (bilNo != null && bilNo.isNotEmpty) return bilNo;
    }
    // resultData 可能是 JSON 字符串
    if (resultData is String && resultData.isNotEmpty) {
      try {
        final parsed = json.decode(resultData) as Map<String, dynamic>;
        final bilNo = parsed['BIL_NO'] as String?;
        if (bilNo != null && bilNo.isNotEmpty) return bilNo;
      } catch (_) {}
    }
    // 兜底: resData 根级 BIL_NO
    final rootBilNo = resData['BIL_NO'] as String?;
    if (rootBilNo != null && rootBilNo.isNotEmpty) return rootBilNo;

    return null;
  }

  /// 下载附件文件字节
  Future<Uint8List?> downloadAttachment(String id) async {
    return await _client.downloadFile(
      '/OA/DownloadAttachment',
      queryParameters: {'id': id},
    );
  }

  /// 检测附件服务是否可用
  Future<bool> checkAttachHealth() async {
    try {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/CheckAttachHealth',
      );
      debugPrint('[checkAttachHealth] response.data: ${response.data}');
      debugPrint(
        '[checkAttachHealth] response.data type: ${response.data.runtimeType}',
      );
      final available = response.data?['available'] as bool? ?? false;
      debugPrint('[checkAttachHealth] available: $available');
      return available;
    } catch (e) {
      debugPrint('[checkAttachHealth] error: $e');
      return false;
    }
  }

  /// 审批进度
  Future<Map<String, dynamic>> fetchApprovalTimeline(
    String bilId,
    String bilNo, {
    int bilItm = 0,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetApprovalTimeline',
      queryParameters: {'bilId': bilId, 'bilNo': bilNo, 'bilItm': bilItm},
    );
    return response.data!;
  }

  /// 获取单据附件列表
  Future<List<BillAttachment>> getAttachments(
    String bilId,
    String bilNo, {
    int? srcItm,
  }) async {
    final params = <String, dynamic>{'bilId': bilId, 'bilNo': bilNo};
    if (srcItm != null) params['srcItm'] = srcItm;
    final response = await _client.get<dynamic>(
      '/OA/GetAttachments',
      queryParameters: params,
    );
    final body = response.data;
    if (body is! Map) return [];
    final result = body['Result'];
    if (result is! Map) return [];
    final documents = result['documents'];
    if (documents is! List) return [];
    return documents
        .whereType<Map<String, dynamic>>()
        .map((e) => BillAttachment.fromJson(e))
        .toList();
  }

  /// 上传附件
  Future<Map<String, dynamic>> uploadAttachment(
    String filePath,
    Map<String, dynamic> metadata,
  ) async {
    final fileName =
        (metadata['FILENAME'] as String?) ?? filePath.split('/').last;
    final response = await _client.uploadMultipart<Map<String, dynamic>>(
      '/OA/UploadAttachment',
      files: [await MultipartFile.fromFile(filePath, filename: fileName)],
      extraFields: {'metadata': json.encode(metadata)},
    );
    return response.data ?? {};
  }

  /// 审核执行（通过/驳回/反审核）
  Future<Map<String, dynamic>> executeApproval({
    required String bilId,
    required String bilNo,
    int bilItm = 0,
    required String action,
    String rem = '',
    String effDd = '',
    String reason = '',
    bool isPreToStart = false,
    int nodeIndex = -1,
    String dataBx = '',
  }) async {
    final response = await _client.post<Map<String, dynamic>>(
      '/OA/ExecuteApproval',
      data: {
        'bilId': bilId,
        'bilNo': bilNo,
        'bilItm': bilItm,
        'action': action,
        'rem': rem,
        'effDd': effDd,
        'reason': reason,
        'isPreToStart': isPreToStart,
        'nodeIndex': nodeIndex,
        'dataBx': dataBx,
      },
    );
    return response.data!;
  }

  /// 费用申请报表
  Future<ReportData> getExpenseApplyReport({
    String? startDate,
    String? endDate,
  }) async {
    final params = <String, dynamic>{};
    if (startDate != null) params['startDate'] = startDate;
    if (endDate != null) params['endDate'] = endDate;
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseApplyReport',
      queryParameters: params,
    );
    return ReportData.fromJson(response.data!);
  }

  /// 费用申请报表明细（分页）
  Future<Map<String, dynamic>> getExpenseApplyReportDetail({
    String? startDate,
    String? endDate,
    int page = 1,
    int size = 20,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseApplyReportDetail',
      queryParameters: {
        'startDate': startDate,
        'endDate': endDate,
        'page': page,
        'size': size,
      },
    );
    return response.data!;
  }

  /// 审核过程明细
  Future<List<Map<String, dynamic>>> getAuditTrail(String billId, String billNo) async {
    final response = await _client.get('/OA/GetAuditTrail', queryParameters: {'billId': billId, 'billNo': billNo});
    final list = (response.data as List<dynamic>?)?.cast<Map<String, dynamic>>() ?? [];
    return list;
  }

  /// 下属报销申请金额对比
  Future<List<SubordinateReportItem>> getExpenseApplySubordinateReport({
    String? startDate,
    String? endDate,
  }) async {
    final params = <String, dynamic>{};
    if (startDate != null) params['startDate'] = startDate;
    if (endDate != null) params['endDate'] = endDate;
    final response = await _client.get<dynamic>(
      '/OA/GetExpenseApplySubordinateReport',
      queryParameters: params,
    );
    final list = (response.data as List<dynamic>?)
            ?.map((e) => SubordinateReportItem.fromJson(e as Map<String, dynamic>))
            .toList() ??
        [];
    return list;
  }

  /// 报销申请单表身明细（分页）
  Future<Map<String, dynamic>> getExpenseApplyBodyReport({
    String? startDate,
    String? endDate,
    int page = 1,
    int size = 20,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseApplyBodyReport',
      queryParameters: {
        if (startDate != null) 'startDate': startDate,
        if (endDate != null) 'endDate': endDate,
        'page': page,
        'size': size,
      },
    );
    return response.data!;
  }

  /// 获取单据状态
  Future<Map<String, dynamic>> getBillStatus(String billNo) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetBillStatus',
      queryParameters: {'billId': 'AE', 'billNo': billNo},
    );
    return response.data!;
  }

  /// 获取指定单据别的附件操作权限
  Future<BillFileRights> getBillFileRights(String billId) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetBillFileRights',
      queryParameters: {'billId': billId},
    );
    return BillFileRights.fromJson(response.data!);
  }

  /// 员工查询
  Future<List<EmployeeItem>> getEmployees({
    String keyword = '',
    String salNo = '',
    int page = 1,
    int size = 100,
  }) async {
    final cacheKey = 'getEmployees_${keyword}_${salNo}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetEmployees',
        queryParameters: {
          'keyword': keyword,
          'salNo': salNo,
          'page': page,
          'size': size,
        },
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => EmployeeItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }
}

class EmployeeItem {
  final String salNo;
  final String name;
  const EmployeeItem({required this.salNo, required this.name});
  factory EmployeeItem.fromJson(Map<String, dynamic> json) => EmployeeItem(
    salNo: json['salNo'] as String? ?? '',
    name: json['name'] as String? ?? '',
  );
}
