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

const DecodeVeh = async (
  extensionlessFilePath: string,
): Promise<DecodedVeh> => {
  let dbf: DBFFile | null = null;
  if (platform.isWindows) {
    try {
      dbf = await DBFFile.open(`${extensionlessFilePath}V.VEH`);
    } catch (error) {
      log.error("Error opening VEH File.", errorTypeCheck(error));
      dbf = await DBFFile.open(`${extensionlessFilePath}.VEH`);
      log.log("Found VEH file using regular CIECA Id.");
    }

    if (!dbf) {
      log.error(`Could not find any VEH files at ${extensionlessFilePath}`);
      throw new Error(
        `Could not find any VEH files at ${extensionlessFilePath}`,
      );
    }
  } else {
    const possibleExtensions: string[] = ["v.veh", ".veh"];
    const filePath = await findFileCaseInsensitive(
      extensionlessFilePath,
      possibleExtensions,
    );
    try {
      if (!filePath) {
        log.error(`Could not find any VEH files at ${extensionlessFilePath}`);
        throw new Error(
          `Could not find any VEH files at ${extensionlessFilePath}`,
        );
      }
      dbf = await DBFFile.open(filePath, { readMode: "loose" });
    } catch (error) {
      log.error("Error opening VEH File.", errorTypeCheck(error));
      throw error;
    }
  }
  const rawDBFRecord = await dbf.readRecords(1);

  //AD2 will always have only 1 row.
  //Commented lines have been cross referenced with existing partner fields.

  //typeCaster is required as the previous partner sent some of these values toString, and the database was made accordingly rather than keeping their original type.
  //Alternative is to change the database schema to match the original type.
  const rawVehData: VehicleRecordInterface = typeCaster(
    deepLowerCaseKeys(
      _.pick(rawDBFRecord[0], [
        //TODO: Add typings for EMS File Formats.
        "IMPACT_1",
        "IMPACT_2",
        "DB_V_CODE",
        "PLATE_NO",
        "PLATE_ST",
        "V_VIN",
        "V_COND",
        "V_PROD_DT",
        "V_MODEL_YR",
        "V_MAKECODE",
        "V_MAKEDESC",
        "V_MODEL",
        "V_TYPE",
        "V_BSTYLE",
        "V_TRIMCODE",
        "TRIM_COLOR",
        "V_MLDGCODE",
        "V_ENGINE",
        "V_MILEAGE",
        "V_COLOR",
        "V_TONE",
        "V_STAGE",
        "PAINT_CD1",
        "PAINT_CD2",
        "PAINT_CD3",
      ]),
    ),
    {
      v_tone: "string",
      v_stage: "string",
    },
  );

  //Apply business logic transfomrations.

  //An old error where the column had an extra underscore.
  rawVehData.v_make_desc = rawVehData.v_makedesc || rawVehData.v_makecode; //Fallback for US.
  delete rawVehData.v_makedesc;
  //An old error where the column had an extra underscore.
  rawVehData.v_model_desc = rawVehData.v_model;
  delete rawVehData.v_model;

  //Consolidate Area of Damage.
  const area_of_damage = {
    impact1: rawVehData.impact_1 ?? "",
    impact2: rawVehData.impact_2 ?? "",
  };
  delete rawVehData.impact_1;
  delete rawVehData.impact_2;

  const kmin = rawVehData.v_mileage ?? 0;
  delete rawVehData.v_mileage;

  //Consolidate Paint Code information.
  rawVehData.v_paint_codes = {
    paint_cd1: rawVehData.paint_cd1 ?? "",
    paint_cd2: rawVehData.paint_cd2 ?? "",
    paint_cd3: rawVehData.paint_cd3 ?? "",
  };
  delete rawVehData.paint_cd1;
  delete rawVehData.paint_cd2;
  delete rawVehData.paint_cd3;

  rawVehData.shopid = store.get("app.bodyshop.id");

  //Aggregate the vehicle data to be stamped onto the job record.
  const jobVehicleData: DecodedVeh = {
    plate_no: rawVehData.plate_no,
    plate_st: rawVehData.plate_st,
    v_vin: rawVehData.v_vin,
    v_model_yr: rawVehData.v_model_yr,
    v_make_desc: rawVehData.v_make_desc,
    v_model_desc: rawVehData.v_model_desc,
    v_color: rawVehData.v_color,
    kmin: kmin,
    area_of_damage: area_of_damage,
    vehicle: {
      data: rawVehData,
    },
  };

  return jobVehicleData;
};

export default DecodeVeh;
