import 'dart:convert';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/network/api_client.dart';
import '../../core/network/api_response.dart';
import '../../app.dart';
import '../../shared/models/pagination_model.dart';
import '../../shared/models/bill_attachment.dart';
import '../../shared/models/bill_file_rights.dart';
import '../../core/navigation/host_app_channel.dart';
import '../../core/utils/date_utils.dart' as du;
import '../../core/data/api_cache.dart';
import 'expense_model.dart';
import 'expense_list_controller.dart';
import '../expense_apply/report_model.dart';

final expenseApiProvider = Provider<ExpenseApi>(
  (ref) => ExpenseApi(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 CustomerItem {
  final String cusNo;
  final String name;
  const CustomerItem({required this.cusNo, required this.name});
  factory CustomerItem.fromJson(Map<String, dynamic> json) => CustomerItem(
    cusNo: json['cusNo'] as String? ?? '',
    name: json['name'] as String? ?? '',
  );
}

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

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

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

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

  /// 费用报销列表（分页）
  Future<PaginatedData<ExpenseModel>> 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/GetExpenseList',
      queryParameters: {
        'status': status,
        'keyword': keyword,
        'startDate': startDate,
        'endDate': endDate,
        'usr': usr,
        'sortDir': sortDir,
        'page': page,
        'size': size,
      },
    );
    return PaginatedData.fromJson(response.data!, ExpenseModel.fromJson);
  }

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

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

    final resultData = resData['resultData'];
    if (resultData is Map<String, dynamic>) {
      final bilNo = resultData['BIL_NO'] as String?;
      if (bilNo != null && bilNo.isNotEmpty) return bilNo;
    }
    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 (_) {}
    }
    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',
      );
      return response.data?['available'] as bool? ?? false;
    } catch (_) {
      return false;
    }
  }

  /// 财务核销
  Future<void> verify(Map<String, dynamic> data) async {
    await _client.post('/OA/ExpenseVerify', data: 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<List<CustomerItem>> getCustomers({
    String keyword = '',
    int page = 1,
    int size = 100,
  }) async {
    final cacheKey = 'getCustomers_${keyword}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetCustomers',
        queryParameters: {'keyword': keyword, 'page': page, 'size': size},
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => CustomerItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 员工查询
  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();
    });
  }

  /// 可转入报销单的费用申请明细（keyword 模糊匹配单号/事由/部门/申请人/费用类型）
  Future<Map<String, dynamic>> getImportableExpenseApplyList({
    String keyword = '',
    String startDate = '',
    String endDate = '',
    int page = 1,
    int size = 20,
    String sortDir = 'DESC',
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetImportableExpenseApplyList',
      queryParameters: {
        'keyword': keyword,
        'startDate': startDate,
        'endDate': endDate,
        'page': page,
        'size': size,
        'sortDir': sortDir,
      },
    );
    return response.data!;
  }

  /// 币别
  Future<List<CurrencyItem>> getCurrencies({
    String keyword = '',
    int page = 1,
    int size = 50,
  }) async {
    final cacheKey = 'getCurrencies_${keyword}_$page';
    return _cache.getOrFetch(cacheKey, () async {
      final response = await _client.get<Map<String, dynamic>>(
        '/OA/GetCurrencies',
        queryParameters: {'keyword': keyword, 'page': page, 'size': size},
      );
      final list = (response.data?['list'] as List<dynamic>?) ?? [];
      return list
          .map((e) => CurrencyItem.fromJson(e as Map<String, dynamic>))
          .toList();
    });
  }

  /// 币别查询（旧版，保留兼容）
  Future<ApiResponse<Map<String, dynamic>>> fetchCurrencies({
    String keyword = '',
    int page = 1,
    int size = 50,
  }) async {
    return await _client.get(
      '/OA/GetCurrencies',
      queryParameters: {'keyword': keyword, 'page': page, 'size': size},
    );
  }

  /// 审批列表
  Future<Map<String, dynamic>> fetchApprovalList({
    required String bilId,
    required String status,
    String erpCategory = 'MasterService',
    String keyword = '',
    String startDate = '',
    String endDate = '',
    int page = 1,
    int size = 20,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetApprovalList',
      queryParameters: {
        'bilId': bilId,
        'status': status,
        'erpCategory': erpCategory,
        'keyword': keyword,
        'startDate': startDate,
        'endDate': endDate,
        'page': page,
        'size': size,
      },
    );
    return response.data!;
  }

  /// 审批进度
  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();
  }

  /// 上传附件
  /// [metadata] Map: { BIL_ID, BIL_NO, SRCITM, ITM, TAG, EFF_DD, USR, FILENAME, EXT }
  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)}, // proper JSON encoding
    );
    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> getExpenseReport({
    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/GetExpenseReport',
      queryParameters: params,
    );
    return ReportData.fromJson(response.data!);
  }

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

  /// 下属报销金额对比
  Future<List<SubordinateReportItem>> getExpenseSubordinateReport({
    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/GetExpenseSubordinateReport',
      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>> getExpenseBodyReport({
    String? startDate,
    String? endDate,
    int page = 1,
    int size = 20,
  }) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/GetExpenseBodyReport',
      queryParameters: {
        if (startDate != null) 'startDate': startDate,
        if (endDate != null) '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<dynamic> getAcctSubjects() async {
    final response = await _client.get('/OA/GetAcctSubjects');
    return response.data;
  }

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

  /// 检查当前用户是否拥有指定特殊密码权限
  Future<bool> checkSpcRight(String ctrlID) async {
    final response = await _client.get<Map<String, dynamic>>(
      '/OA/CheckSpcRight',
      queryParameters: {'ctrlID': ctrlID},
    );
    return response.data?['hasRight'] == true;
  }

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

/// 费用报销审批列表项
class ExpenseApprovalListItem {
  final String bilId;
  final String bilNo;
  final String bilDate;
  final String applicant;
  final String dept;
  final double amount;
  final String remark;
  final String status;

  const ExpenseApprovalListItem({
    required this.bilId,
    required this.bilNo,
    required this.bilDate,
    required this.applicant,
    required this.dept,
    required this.amount,
    required this.remark,
    required this.status,
  });

  factory ExpenseApprovalListItem.fromJson(Map<String, dynamic> json) =>
      ExpenseApprovalListItem(
        bilId: json['bilId'] as String? ?? '',
        bilNo: json['bilNo'] as String? ?? '',
        bilDate: json['bilDate'] as String? ?? '',
        applicant: json['applicant'] as String? ?? '',
        dept: json['dept'] as String? ?? '',
        amount: (json['amount'] as num?)?.toDouble() ?? 0,
        remark: json['remark'] as String? ?? '',
        status: json['status'] as String? ?? 'pending',
      );

  ExpenseModel toExpenseModel() => ExpenseModel(
    id: bilNo,
    expenseNo: bilNo,
    expenseDate: bilDate.isNotEmpty ? DateTime.tryParse(bilDate) : null,
    applicantId: applicant,
    applicantName: applicant,
    deptId: dept,
    deptName: dept,
    totalAmount: amount,
    purpose: remark,
    status: status == 'approved' ? 'approved' : 'pending',
    paymentStatus: 'unpaid',
    createTime: DateTime.now(),
    updateTime: DateTime.now(),
  );
}

final expenseApprovalListProvider = FutureProvider.autoDispose
    .family<List<ExpenseModel>, String>((ref, status) async {
      ref.watch(expenseRefreshProvider);
      ref.watch(expenseDateStartProvider);
      ref.watch(expenseDateEndProvider);
      ref.watch(expenseKeywordProvider);

      final api = ref.read(expenseApiProvider);
      final dateStart = ref.read(expenseDateStartProvider);
      final dateEnd = ref.read(expenseDateEndProvider);
      final keyword = ref.read(expenseKeywordProvider);

      final response = await api.fetchApprovalList(
        bilId: 'BX',
        keyword: keyword,
        status: status.isEmpty ? '' : status,
        startDate: dateStart != null ? du.DateUtils.formatDate(dateStart) : '',
        endDate: dateEnd != null ? du.DateUtils.formatDate(dateEnd) : '',
      );
      return (response['list'] as List<dynamic>?)
              ?.map(
                (e) => ExpenseApprovalListItem.fromJson(
                  e as Map<String, dynamic>,
                ).toExpenseModel(),
              )
              .toList() ??
          [];
    });

/// "我的报销单" 列表（制单人=当前用户，非审批流）
final expenseMyListProvider = FutureProvider.autoDispose
    .family<List<ExpenseModel>, String>((ref, status) async {
      ref.watch(expenseRefreshProvider);
      ref.watch(expenseDateStartProvider);
      ref.watch(expenseDateEndProvider);
      ref.watch(expenseKeywordProvider);

      final api = ref.read(expenseApiProvider);
      final dateStart = ref.read(expenseDateStartProvider);
      final dateEnd = ref.read(expenseDateEndProvider);
      final keyword = ref.read(expenseKeywordProvider);

      final result = await api.fetchList(
        keyword: keyword,
        startDate: dateStart != null ? du.DateUtils.formatDate(dateStart) : '',
        endDate: dateEnd != null ? du.DateUtils.formatDate(dateEnd) : '',
        usr: HostAppChannel.usr,
        sortDir: ref.watch(expenseSortDirProvider),
      );
      return result.list;
    });
