import { platform } from "@electron-toolkit/utils";
import { DBFFile } from "dbffile";
import log from "electron-log/main";
import _ from "lodash";
import deepLowerCaseKeys from "../../util/deepLowercaseKeys";
import errorTypeCheck from "../../util/errorTypeCheck";
import store from "../store/store";
import { DecodedAd1, OwnerRecordInterface } from "./decode-ad1.interface";
import { findFileCaseInsensitive } from "./decoder-utils";

const DecodeAD1 = async (
  extensionlessFilePath: string,
): Promise<DecodedAd1> => {
  let dbf: DBFFile | null = null;

  if (platform.isWindows) {
    try {
      dbf = await DBFFile.open(`${extensionlessFilePath}A.AD1`);
    } catch {
      // log.debug("Error opening AD1 File.", errorTypeCheck(error));
      dbf = await DBFFile.open(`${extensionlessFilePath}.AD1`);
      // log.debug("Trying to find AD1 file using regular CIECA Id.");
    }

    if (!dbf) {
      log.error(`Could not find any AD1 files at ${extensionlessFilePath}`);
      throw new Error(
        `Could not find any AD1 files at ${extensionlessFilePath}`,
      );
    }
  } else {
    const possibleExtensions: string[] = ["a.ad1", ".ad1"];
    const filePath = await findFileCaseInsensitive(
      extensionlessFilePath,
      possibleExtensions,
    );
    try {
      if (!filePath) {
        log.error(`Could not find any AD1 files at ${extensionlessFilePath}`);
        throw new Error(
          `Could not find any AD1 files at ${extensionlessFilePath}`,
        );
      }
      dbf = await DBFFile.open(filePath);
    } catch (error) {
      log.error("Error opening AD1 File.", errorTypeCheck(error));
      throw error;
    }
  }

  const rawDBFRecord = await dbf.readRecords(1);

  //AD1 will always have only 1 row.
  //Commented lines have been cross referenced with existing partner fields.
  const rawAd1Data: DecodedAd1 = deepLowerCaseKeys(
    _.pick(rawDBFRecord[0], [
      //TODO: Add typings for EMS File Formats.
      "INS_CO_ID",
      "INS_CO_NM",
      "INS_ADDR1",
      "INS_ADDR2",
      "INS_CITY",
      "INS_ST",
      "INS_ZIP",
      "INS_CTRY",
      "INS_EA",
      "POLICY_NO",
      "DED_AMT",
      "DED_STATUS",
      "ASGN_NO",
      "ASGN_DATE",
      "ASGN_TYPE",
      "CLM_NO",
      "CLM_OFC_ID",
      "CLM_OFC_NM",
      "CLM_ADDR1",
      "CLM_ADDR2",
      "CLM_CITY",
      "CLM_ST",
      "CLM_ZIP",
      "CLM_CTRY",
      "CLM_PH1",
      "CLM_PH1X",
      "CLM_PH2",
      "CLM_PH2X",
      "CLM_FAX",
      "CLM_FAXX",
      "CLM_CT_LN",
      "CLM_CT_FN",
      "CLM_TITLE",
      "CLM_CT_PH",
      "CLM_CT_PHX",
      "CLM_EA",
      "PAYEE_NMS",
      "PAY_TYPE",
      "PAY_DATE",
      "PAY_CHKNM",
      "PAY_AMT",
      "AGT_CO_ID",
      "AGT_CO_NM",
      "AGT_ADDR1",
      "AGT_ADDR2",
      "AGT_CITY",
      "AGT_ST",
      "AGT_ZIP",
      "AGT_CTRY",
      "AGT_PH1",
      "AGT_PH1X",
      "AGT_PH2",
      "AGT_PH2X",
      "AGT_FAX",
      "AGT_FAXX",
      "AGT_CT_LN",
      "AGT_CT_FN",
      "AGT_CT_PH",
      "AGT_CT_PHX",
      "AGT_EA",
      "AGT_LIC_NO",
      "LOSS_DATE",
      "LOSS_TYPE",
      "LOSS_DESC",
      "THEFT_IND",
      "CAT_NO",
      "TLOS_IND",
      "CUST_PR",
      "INSD_LN",
      "INSD_FN",
      "INSD_TITLE",
      "INSD_CO_NM",
      "INSD_ADDR1",
      "INSD_ADDR2",
      "INSD_CITY",
      "INSD_ST",
      "INSD_ZIP",
      "INSD_CTRY",
      "INSD_PH1",
      //"INSD_PH1X",
      "INSD_PH2",
      //"INSD_PH2X",
      "INSD_FAX",
      "INSD_FAXX",
      "INSD_EA",
      "OWNR_LN",
      "OWNR_FN",
      "OWNR_TITLE",
      "OWNR_CO_NM",
      "OWNR_ADDR1",
      "OWNR_ADDR2",
      "OWNR_CITY",
      "OWNR_ST",
      "OWNR_ZIP",
      "OWNR_CTRY",
      "OWNR_PH1",
      //"OWNR_PH1X",
      "OWNR_PH2",
      //"OWNR_PH2X",
      //"OWNR_FAX",
      //"OWNR_FAXX",
      "OWNR_EA",
      "INS_PH1",
      "INS_PH1X",
      "INS_PH2",
      "INS_PH2X",
      "INS_FAX",
      "INS_FAXX",
      "INS_CT_LN",
      "INS_CT_FN",
      "INS_TITLE",
      "INS_CT_PH",
      "INS_CT_PHX",
      "LOSS_CAT",
    ]),
  );

  //Copy specific logic for manipulation.
  //If ownr_ph1 is missing, use ownr_ph2
  if (rawAd1Data.asgn_date) {
    const newAsgnDate = new Date(rawAd1Data.asgn_date);
    rawAd1Data.asgn_date = newAsgnDate.toISOString().split("T")[0];
  }

  if (!rawAd1Data.ownr_ph1 || _.isEmpty(rawAd1Data.ownr_ph1)) {
    rawAd1Data.ownr_ph1 = rawAd1Data.ownr_ph2;
  }
  if (rawAd1Data.clm_no === "") {
    rawAd1Data.clm_no = undefined;
  }
  let ownerRecord: OwnerRecordInterface;
  //Check if the owner information is there. If not, use the insured information as a fallback.
  if (
    _.isEmpty(rawAd1Data.ownr_ln) &&
    _.isEmpty(rawAd1Data.ownr_fn) &&
    _.isEmpty(rawAd1Data.ownr_co_nm)
  ) {
    //They're all empty. Using the insured information as a fallback.
    // Build up the owner record to insert it alongside the job.
    //TODO: Verify that this should be the insured, and not the claimant.
    ownerRecord = {
      ownr_ln: rawAd1Data.insd_ln,
      ownr_fn: rawAd1Data.insd_fn,
      ownr_title: rawAd1Data.insd_title,
      ownr_co_nm: rawAd1Data.insd_co_nm,
      ownr_addr1: rawAd1Data.insd_addr1,
      ownr_addr2: rawAd1Data.insd_addr2,
      ownr_city: rawAd1Data.insd_city,
      ownr_st: rawAd1Data.insd_st,
      ownr_zip: rawAd1Data.insd_zip,
      ownr_ctry: rawAd1Data.insd_ctry,
      ownr_ph1: rawAd1Data.insd_ph1,
      ownr_ph2: rawAd1Data.insd_ph2,
      ownr_ea: rawAd1Data.insd_ea,
      shopid: store.get("app.bodyshop.id"),
    };
  } else {
    //Use the owner information.
    ownerRecord = {
      ownr_ln: rawAd1Data.ownr_ln,
      ownr_fn: rawAd1Data.ownr_fn,
      ownr_title: rawAd1Data.ownr_title,
      ownr_co_nm: rawAd1Data.ownr_co_nm,
      ownr_addr1: rawAd1Data.ownr_addr1,
      ownr_addr2: rawAd1Data.ownr_addr2,
      ownr_city: rawAd1Data.ownr_city,
      ownr_st: rawAd1Data.ownr_st,
      ownr_zip: rawAd1Data.ownr_zip,
      ownr_ctry: rawAd1Data.ownr_ctry,
      ownr_ph1: rawAd1Data.ownr_ph1,
      ownr_ph2: rawAd1Data.ownr_ph2,
      ownr_ea: rawAd1Data.ownr_ea,
      shopid: store.get("app.bodyshop.id"),
    };
  }

  return { ...rawAd1Data, owner: { data: ownerRecord } };
};

export default DecodeAD1;
