package com.example.idcard;

import androidx.annotation.NonNull;
import android.content.Context;
import android.util.Log;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

import com.sdses.JniCommonInterface;

import java.util.HashMap;
import java.util.Map;

/**
 * IdcardPlugin - Flutter插件，用于身份证识别功能
 * 集成了01SDK的身份证读取功能
 */
public class IdcardPlugin implements FlutterPlugin, MethodCallHandler {
  private static final String TAG = "IdcardPlugin";
  
  /// 与Flutter通信的方法通道
  private MethodChannel channel;
  private Context context;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "idcard");
    channel.setMethodCallHandler(this);
    context = flutterPluginBinding.getApplicationContext();
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    try {
      switch (call.method) {
        case "getPlatformVersion":
          result.success("Android " + android.os.Build.VERSION.RELEASE);
          break;
        case "openDevice":
          handleOpenDevice(call, result);
          break;
        case "setCurrentDevice":
          handleSetCurrentDevice(call, result);
          break;
        case "getCurrentDevice":
          handleGetCurrentDevice(result);
          break;
        case "getLibraryInfo":
          handleGetLibraryInfo(result);
          break;
        case "getTerminalModel":
          handleGetTerminalModel(result);
          break;
        case "terminalHeartBeat":
          handleTerminalHeartBeat(result);
          break;
        case "getLastRecvData":
          handleGetLastRecvData(result);
          break;
        case "getTerminalFirmVersion":
          handleGetTerminalFirmVersion(result);
          break;
        case "getTerminalSn":
          handleGetTerminalSn(result);
          break;
        case "closeDevice":
          handleCloseDevice(result);
          break;
        case "findCard":
          handleFindCard(result);
          break;
        case "selectCard":
          handleSelectCard(result);
          break;
        case "idReadCard":
          handleIdReadCard(call, result);
          break;
        case "readCard":
          handleReadCard(call, result);
          break;
        case "readCardInfo":
          handleReadCardInfo(result);
          break;
        case "readNewAddress":
          handleReadNewAddress(result);
          break;
        case "getSamStatus":
          handleGetSamStatus(result);
          break;
        case "getSamIdStr":
          handleGetSamIdStr(result);
          break;
        case "getUsbPermission":
          handleGetUsbPermission(call, result);
          break;
        default:
          result.notImplemented();
          break;
      }
    } catch (Exception e) {
      Log.e(TAG, "Error in method call: " + call.method, e);
      result.error("ERROR", "Method call failed: " + e.getMessage(), null);
    }
  }

  /**
   * 获取USB权限
   */
  private void handleGetUsbPermission(MethodCall call, Result result) {
    Integer vid = call.argument("vid");
    Integer pid = call.argument("pid");
    
    if (vid == null || pid == null) {
      result.error("INVALID_PARAMS", "VID and PID are required", null);
      return;
    }
    
    try {
      long ret = JniCommonInterface.GetUsbPermission(context, vid, pid);
      
      // 根据返回值提供更详细的错误信息
      switch ((int)ret) {
        case 0:
          result.success(ret);
          break;
        case -1:
          result.error("DEVICE_NOT_FOUND", "未找到指定的USB设备 (VID:" + vid + ", PID:" + pid + ")", null);
          break;
        case -2:
          result.error("INTERFACE_ERROR", "USB设备接口错误", null);
          break;
        case -3:
          result.error("PERMISSION_DENIED", "USB权限请求被拒绝或超时，请在系统设置中手动授权USB权限", null);
          break;
        case -99:
          result.error("UNKNOWN_ERROR", "获取USB权限时发生未知错误", null);
          break;
        default:
          result.error("ERROR", "获取USB权限失败，错误码: " + ret, null);
          break;
      }
    } catch (Exception e) {
      result.error("EXCEPTION", "获取USB权限时发生异常: " + e.getMessage(), null);
    }
  }

  /**
   * 打开设备
   */
  private void handleOpenDevice(MethodCall call, Result result) {
    try {
      String portType = call.argument("portType");
      String portPara = call.argument("portPara");
      String extendPara = call.argument("extendPara");
      
      if (portType == null) portType = "USB";
      if (portPara == null) portPara = "";
      if (extendPara == null) extendPara = "";
      
      long deviceHandle = JniCommonInterface.OpenDevice(portType, portPara, extendPara);
      
      // 根据接口文档，返回值大于0表示成功（设备句柄），小于等于0表示失败
      if (deviceHandle > 0) {
        result.success(deviceHandle);
      } else {
        result.error("OPEN_DEVICE_FAILED", "Failed to open device, error code: " + deviceHandle, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error opening device", e);
      result.error("ERROR", "Failed to open device: " + e.getMessage(), null);
    }
  }

  /**
   * 关闭设备
   */
  private void handleCloseDevice(Result result) {
    try {
      long closeResult = JniCommonInterface.CloseDevice();
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (closeResult == 0) {
        result.success(closeResult);
      } else {
        result.error("CLOSE_DEVICE_FAILED", "Failed to close device, error code: " + closeResult, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error closing device", e);
      result.error("ERROR", "Failed to close device: " + e.getMessage(), null);
    }
  }

  /**
   * 寻卡
   */
  private void handleFindCard(Result result) {
    try {
      long findResult = JniCommonInterface.IdFindCard();

      if (findResult == 0) {
        result.success(findResult);
      } else {
        result.error("FIND_CARD_FAILED", "Failed to find card, error code: " + findResult, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error finding card", e);
      result.error("ERROR", "Failed to find card: " + e.getMessage(), null);
    }
  }

  /**
   * 选卡
   */
  private void handleSelectCard(Result result) {
    try {
      long selectResult = JniCommonInterface.IdSelectCard();

      if (selectResult == 0) {
        result.success(selectResult);
      } else {
        result.error("SELECT_CARD_FAILED", "Failed to select card, error code: " + selectResult, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error selecting card", e);
      result.error("ERROR", "Failed to select card: " + e.getMessage(), null);
    }
  }

  /**
   * 读取身份证信息
   */
  private void handleReadCard(MethodCall call, Result result) {
    Integer cardType = call.argument("cardType");
    Integer infoEncoding = call.argument("infoEncoding");
    Integer timeOut = call.argument("timeOut");
    
    if (cardType == null) cardType = 1;
    if (infoEncoding == null) infoEncoding = 0;
    if (timeOut == null) timeOut = 30000;
    
    byte[] idCardInfo = new byte[4096];
    long ret = JniCommonInterface.IdReadCard((byte)cardType.intValue(), 
                                           (byte)infoEncoding.intValue(), 
                                           idCardInfo, 
                                           timeOut);
    
    Map<String, Object> resultMap = new HashMap<>();
    resultMap.put("result", ret);
    // 根据接口文档，返回值0表示成功；非0表示失败
    if (ret == 0) {
      resultMap.put("data", idCardInfo);
    }
    result.success(resultMap);
  }

  /**
   * 读取身份证详细信息
   */
  private void handleReadCardInfo(Result result) {
    try {
      // 读取基本信息和照片
      byte[] chMsg = new byte[256];
      long[] chMsgLen = new long[1];
      byte[] phMsg = new byte[1024];
      long[] phMsgLen = new long[1];
      
      long ret = JniCommonInterface.IdReadBaseMsg(chMsg, chMsgLen, phMsg, phMsgLen);
      
      if (ret != 0) {
        result.error("READ_failed", "Failed to read card info, error code: " + ret, null);
        return;
      }
      
      // 解析身份证信息
      Map<String, Object> cardInfo = new HashMap<>();
      
      // 获取各个字段
      byte[] name = new byte[32];
      byte[] gender = new byte[4];
      byte[] nation = new byte[32];
      byte[] birthDate = new byte[16];
      byte[] address = new byte[128];
      byte[] idNumber = new byte[32];
      byte[] signOrgan = new byte[64];
      byte[] validTerm = new byte[32];
      
      JniCommonInterface.IdCardGetName(name);
      JniCommonInterface.IdCardGetGender(gender);
      JniCommonInterface.IdCardGetNation(nation);
      JniCommonInterface.IdCardGetBirthDate(birthDate);
      JniCommonInterface.IdCardGetAddress(address);
      JniCommonInterface.IdCardGetIdNumber(idNumber);
      JniCommonInterface.IdCardGetSignOrgan(signOrgan);
      JniCommonInterface.IdCardGetValidTerm(validTerm);
      
      // 获取照片
      byte[] photoBuffer = new byte[10240];
      long[] photoBufferLen = new long[1];
      JniCommonInterface.IdCardGetPhotoBuffer((byte)1, photoBuffer, photoBufferLen);
      
      cardInfo.put("name", new String(name, "GBK").trim());
      cardInfo.put("gender", new String(gender, "GBK").trim());
      cardInfo.put("nation", new String(nation, "GBK").trim());
      cardInfo.put("birthDate", new String(birthDate, "GBK").trim());
      cardInfo.put("address", new String(address, "GBK").trim());
      cardInfo.put("idNumber", new String(idNumber, "GBK").trim());
      cardInfo.put("signOrgan", new String(signOrgan, "GBK").trim());
      cardInfo.put("validTerm", new String(validTerm, "GBK").trim());
      
      if (photoBufferLen[0] > 0) {
        byte[] photo = new byte[(int)photoBufferLen[0]];
        System.arraycopy(photoBuffer, 0, photo, 0, (int)photoBufferLen[0]);
        cardInfo.put("photo", photo);
      }
      
      result.success(cardInfo);
      
    } catch (Exception e) {
      Log.e(TAG, "Error reading card info", e);
      result.error("ERROR", "Failed to read card2 info: " + e.getMessage(), null);
    }
  }

  /**
   * 设置当前设备（多设备操作）
   */
  private void handleSetCurrentDevice(MethodCall call, Result result) {
    try {
      Integer devHandle = call.argument("devHandle");
      if (devHandle == null) {
        result.error("INVALID_PARAMS", "Device handle is required", null);
        return;
      }
      
      long ret = JniCommonInterface.SetCurrentDevice(devHandle);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        result.success(ret);
      } else {
        result.error("SET_CURRENT_DEVICE_FAILED", "Failed to set current device, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error setting current device", e);
      result.error("ERROR", "Failed to set current device: " + e.getMessage(), null);
    }
  }

  /**
   * 获取当前设备（多设备操作）
   */
  private void handleGetCurrentDevice(Result result) {
    try {
      long currentDevice = JniCommonInterface.GetCurrentDevice();
      result.success(currentDevice);
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting current device", e);
      result.error("ERROR", "Failed to get current device: " + e.getMessage(), null);
    }
  }

  /**
   * 获取接口库信息
   */
  private void handleGetLibraryInfo(Result result) {
    try {
      byte[] version = new byte[64];
      byte[] description = new byte[256];
      
      long ret = JniCommonInterface.GetLibraryInfo(version, description);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        Map<String, String> info = new HashMap<>();
        info.put("version", new String(version, "GBK").trim());
        info.put("description", new String(description, "GBK").trim());
        result.success(info);
      } else {
        result.error("GET_LIBRARY_INFO_FAILED", "Failed to get library info, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting library info", e);
      result.error("ERROR", "Failed to get library info: " + e.getMessage(), null);
    }
  }

  /**
   * 获取设备型号
   */
  private void handleGetTerminalModel(Result result) {
    try {
      byte[] model = new byte[64];
      long ret = JniCommonInterface.GetTerminalModel(model);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        String modelStr = new String(model, "GBK").trim();
        result.success(modelStr);
      } else {
        result.error("GET_TERMINAL_MODEL_FAILED", "Failed to get terminal model, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting terminal model", e);
      result.error("ERROR", "Failed to get terminal model: " + e.getMessage(), null);
    }
  }

  /**
   * 设备轮询心跳
   */
  private void handleTerminalHeartBeat(Result result) {
    try {
      long ret = JniCommonInterface.TerminalHeartBeat();
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        result.success(ret);
      } else {
        result.error("TERMINAL_HEARTBEAT_FAILED", "Terminal heartbeat failed, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error in terminal heart beat", e);
      result.error("ERROR", "Failed to perform terminal heart beat: " + e.getMessage(), null);
    }
  }

  /**
   * 获取接收数据
   */
  private void handleGetLastRecvData(Result result) {
    try {
      byte[] data = new byte[1024];
      long[] dataLen = new long[1];
      
      JniCommonInterface.GetLastRecvData(data, dataLen);
      
      if (dataLen[0] > 0) {
        byte[] actualData = new byte[(int)dataLen[0]];
        System.arraycopy(data, 0, actualData, 0, (int)dataLen[0]);
        result.success(actualData);
      } else {
        result.success(new byte[0]);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting last recv data", e);
      result.error("ERROR", "Failed to get last recv data: " + e.getMessage(), null);
    }
  }

  /**
   * 获取设备固件版本
   */
  private void handleGetTerminalFirmVersion(Result result) {
    try {
      byte[] firmVersion = new byte[64];
      byte[] hardwareVersion = new byte[64];
      
      long ret = JniCommonInterface.GetTerminalFirmVersion(firmVersion, hardwareVersion);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        Map<String, String> versionInfo = new HashMap<>();
        versionInfo.put("firmVersion", new String(firmVersion, "GBK").trim());
        versionInfo.put("hardwareVersion", new String(hardwareVersion, "GBK").trim());
        result.success(versionInfo);
      } else {
        result.error("GET_FIRM_VERSION_FAILED", "Failed to get terminal firm version, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting terminal firm version", e);
      result.error("ERROR", "Failed to get terminal firm version: " + e.getMessage(), null);
    }
  }

  /**
   * 获取设备序列号
   */
  private void handleGetTerminalSn(Result result) {
    try {
      byte[] sn = new byte[64];
      long ret = JniCommonInterface.GetTerminalSn(sn);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        String snStr = new String(sn, "GBK").trim();
        result.success(snStr);
      } else {
        result.error("GET_TERMINAL_SN_FAILED", "Failed to get terminal SN, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting terminal SN", e);
      result.error("ERROR", "Failed to get terminal SN: " + e.getMessage(), null);
    }
  }

  /**
   * 读取身份证（新版接口）
   */
  private void handleIdReadCard(MethodCall call, Result result) {
    try {
      Integer cardType = call.argument("cardType");
      Integer infoEncoding = call.argument("infoEncoding");
      Integer timeOut = call.argument("timeOut");
      
      if (cardType == null) cardType = 0x00;
      if (infoEncoding == null) infoEncoding = 0x01;
      if (timeOut == null) timeOut = 30000;
      
      byte[] idCardInfo = new byte[4096];
      long ret = JniCommonInterface.IdReadCard((byte)cardType.intValue(), 
                                             (byte)infoEncoding.intValue(), 
                                             idCardInfo, 
                                             timeOut);
      
      Map<String, Object> resultMap = new HashMap<>();
      resultMap.put("result", ret);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        // 将字节数组转换为字符串（根据编码方式）
        String encoding = "GBK";
        if (infoEncoding == 0x02) {
          encoding = "UTF-16LE";
        } else if (infoEncoding == 0x03) {
          encoding = "UTF-8";
        }
        
        // 找到字节数组中第一个null字符的位置
        int length = 0;
        for (int i = 0; i < idCardInfo.length; i++) {
          if (idCardInfo[i] == 0) {
            length = i;
            break;
          }
        }
        
        // 如果没有找到null字符，使用整个数组长度
        if (length == 0) {
          length = idCardInfo.length;
        }
        
        // 只转换有效的字节数据
        String dataStr = new String(idCardInfo, 0, length, encoding).trim();
        resultMap.put("data", dataStr);
        
        Log.d(TAG, "IdReadCard success, data length: " + length + ", data: " + dataStr);
      } else {
        Log.e(TAG, "IdReadCard failed with error code: " + ret);
      }
      
      result.success(resultMap);
      
    } catch (Exception e) {
      Log.e(TAG, "Error in idReadCard", e);
      result.error("ERROR", "Failed to read card: " + e.getMessage(), null);
    }
  }

  /**
   * 读取追加住址
   */
  private void handleReadNewAddress(Result result) {
    try {
      byte[] address = new byte[256];
      long ret = JniCommonInterface.IdReadNewAddress(address);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        String addressStr = new String(address, "GBK").trim();
        result.success(addressStr);
      } else {
        result.error("READ_failed", "Failed to read new address, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error reading new address", e);
      result.error("ERROR", "Failed to read new address: " + e.getMessage(), null);
    }
  }

  /**
   * 获取SAM模块状态
   */
  private void handleGetSamStatus(Result result) {
    try {
      long status = JniCommonInterface.GetSamStatus();
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (status == 0) {
        result.success(0); // 成功时返回0
      } else {
        result.error("SAM_STATUS_ERROR", "SAM module status error, code: " + status, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting SAM status", e);
      result.error("ERROR", "Failed to get SAM status: " + e.getMessage(), null);
    }
  }

  /**
   * 获取SAM模块编号字符串
   */
  private void handleGetSamIdStr(Result result) {
    try {
      byte[] samId = new byte[64];
      long ret = JniCommonInterface.GetSamIdStr(samId);
      
      // 根据接口文档，返回值0表示成功；非0表示失败
      if (ret == 0) {
        String samIdStr = new String(samId, "GBK").trim();
        result.success(samIdStr);
      } else {
        result.error("GET_SAM_ID_FAILED", "Failed to get SAM ID string, error code: " + ret, null);
      }
      
    } catch (Exception e) {
      Log.e(TAG, "Error getting SAM ID string", e);
      result.error("ERROR", "Failed to get SAM ID string: " + e.getMessage(), null);
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}
