import { Column } from "common/ResponsiveTable";
import { Option } from "common/SearchSelect";
import GrainDescriber from "grain/GrainDescriber";
//import { Column } from "material-table";
import { Bin, BinYard, Field } from "models";
//import { Gate } from "models/Gate";
import { GrainBag } from "models/GrainBag";
//import { ObjectHeater } from "models/ObjectHeater";
import { pond } from "protobuf-ts/pond";
import { getDistanceUnit, getTemperatureUnit } from "utils";

interface Sort {
  order: string; //what to send to the backend list to sort by
  numerical: boolean; //whether to use a numerical or text sort
}

export interface ObjectExtension {
  name: string;
  inventoryGroup: string;
  isTransactionObject: boolean;
  //this will define the columns to be used for the object in a material table
  tableColumns: Column<any>[];
  //this map will match the title of the column to what the backend needs to perform the ordering
  tableSort: Map<string, Sort>;
}

const defaultObject: ObjectExtension = {
  name: "None",
  inventoryGroup: "",
  isTransactionObject: false,
  tableColumns: [],
  tableSort: new Map()
};

export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
  [pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject],
  [
    pond.ObjectType.OBJECT_TYPE_BACKPACK,
    {
      name: "Backpack",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_BIN,
    {
      name: "Bin",
      inventoryGroup: "grain",
      isTransactionObject: true,
      tableColumns: [
        {
          title: "Name",
          cellStyle: {padding: "16px"},
          render: row => {
            return (<div>{row.settings.name}</div>);
          }
        },
        {
          title: "Grain",
          cellStyle: {padding: "16px"},
          render: row => {
            let grain = row.settings.inventory?.grainType;
            if (grain) {
              return GrainDescriber(grain).name;
            }
          }
        },
        {
          title: "Bin Height",
          cellStyle: {padding: "16px"},
          render: row => {
            let d = row.settings.specs?.heightCm;
            if (d) {
              if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                return (d / 100).toFixed(2) + " m";
              } else {
                return (d / 30.48).toFixed(2) + " ft";
              }
            }
          }
        },
        {
          title: "Bin Diameter",
          cellStyle: {padding: "16px"},
          render: row => {
            let d = row.settings.specs?.diameterCm;
            if (d) {
              if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                return (d / 100).toFixed(2) + " m";
              } else {
                return (d / 30.48).toFixed(2) + " ft";
              }
            }
          }
        },
        {
          title: "Custom Grain Name",
          cellStyle: {padding: "16px"},
          render: row => {
            return row.settings.inventory?.customTypeName;
          }
        },
        {
          title: "Grain Variant",
          cellStyle: {padding: "16px"},
          render: row => {
            return row.settings.inventory?.grainSubtype;
          }
        },
        {
          title: "Grain Bushels",
          cellStyle: {padding: "16px"},
          render: row => {
            return (<div>{row.settings.inventory ? isNaN(row.settings.inventory.grainBushels) ? 0 : row.settings.inventory.grainBushels : 0}</div>);
          }
        },
        {
          title: "Grain Capacity",
          cellStyle: {padding: "16px"},
          render: row => {
            return row.settings.specs?.bushelCapacity;
          }
        },
        {
          title: "High Temp Warning",
          cellStyle: {padding: "16px"},
          render: row => {
            let t = row.settings.highTemp;
            if (t) {
              if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                return (t * 1.8 + 32).toFixed(2) + " °F";
              } else {
                return t.toFixed(2) + " °C";
              }
            }
          }
        },
        {
          title: "Low Temp Warning",
          cellStyle: {padding: "16px"},
          render: row => {
            let t = row.settings.lowTemp;
            if (t) {
              if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
                return (t * 1.8 + 32).toFixed(2) + " °F";
              } else {
                return t.toFixed(2) + " °C";
              }
            }
          }
        }
      ] as Column<Bin>[],
      tableSort: new Map([
        ["Name", { order: "name", numerical: false }],
        ["Grain", { order: "inventory.grainType", numerical: false }],
        ["Bin Height", { order: "specs.heightCm", numerical: true }],
        ["Bin Diameter", { order: "specs.diameterCm", numerical: true }],
        ["Custom Grain Name", { order: "inventory.customTypeName", numerical: false }],
        ["Grain Variant", { order: "inventory.grainSubtype", numerical: false }],
        ["Grain Bushels", { order: "inventory.grainBushels", numerical: true }],
        ["Grain Capacity", { order: "specs.bushelCapacity", numerical: true }],
        ["High Temp Warning", { order: "highTemp", numerical: true }],
        ["Low Temp Warning", { order: "lowTemp", numerical: true }]
      ])
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_BINYARD,
    {
      name: "Binyard",
      inventoryGroup: "grain",
      isTransactionObject: false,
      tableColumns: [
        {
          title: "Name",
          render: row => {
            return (<div>{row.settings.name}</div>)
          }
        },
        {
          title: "Description",
          render: row => {
            return row.settings.description;
          }
        }
      ] as Column<BinYard>[],
      tableSort: new Map([
        ["Name", { order: "name", numerical: false }],
        ["Description", { order: "description", numerical: false }]
      ])
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_COMPONENT,
    {
      name: "Component",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_DEVICE,
    {
      name: "Device",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_FIELD,
    {
      name: "Field",
      inventoryGroup: "grain",
      isTransactionObject: true,
      tableColumns: [
        {
          title: "Name",
          render: row => {
            return (<div>{row.settings.fieldName}</div>)
          }
        },
        {
          title: "Land Location",
          render: row => {
            return row.settings.landLocation;
          }
        },
        {
          title: "Crop",
          render: row => {
            return GrainDescriber(row.settings.crop).name;
          }
        },
        {
          title: "Custom",
          render: row => {
            return row.settings.customGrain;
          }
        },
        {
          title: "Grain Variant",
          render: row => {
            return row.settings.grainSubtype;
          }
        }
        // {
        //   title: "Sowing Date",
        //   render: row => {
        //     return row.settings.sowingDate
        //   }
        // }
      ] as Column<Field>[],
      tableSort: new Map([
        ["Name", { order: "fieldName", numerical: false }],
        ["Land Location", { order: "landLocation", numerical: false }],
        ["Crop", { order: "crop", numerical: false }],
        ["Custom", { order: "customGrain", numerical: false }],
        ["Grain Variant", { order: "grainSubtype", numerical: false }]
        //["Sowing Date", { order: "sowingDate", numerical: true}]
      ])
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_FIELDMARKER,
    {
      name: "Field Marker",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_FIRMWARE,
    {
      name: "Firmware",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  // [
  //   pond.ObjectType.OBJECT_TYPE_GATE,
  //   {
  //     name: "Gate",
  //     inventoryGroup: "",
  //     isTransactionObject: false,
  //     tableColumns: [
  //       {
  //         title: "Name",
  //         render: row => {
  //           if (row.name) {
  //             return row.name.toString();
  //           }
  //         }
  //       },
  //       {
  //         title: "PCA Type",
  //         render: row => {
  //           return row.settings.pcaType;
  //         }
  //       },
  //       {
  //         title: "Hourly APU Cost",
  //         render: row => {
  //           if (row.settings.hourlyApuCost) {
  //             return "$" + row.settings.hourlyApuCost.toFixed(2);
  //           }
  //         }
  //       },
  //       {
  //         title: "Hourly PCA Cost",
  //         render: row => {
  //           if (row.settings.hourlyPcaCost) {
  //             return "$" + row.settings.hourlyPcaCost.toFixed(2);
  //           }
  //         }
  //       },
  //       {
  //         title: "Upper Flow",
  //         render: row => {
  //           return row.settings.upperFlow;
  //         }
  //       },
  //       {
  //         title: "Lower Flow",
  //         render: row => {
  //           return row.settings.lowerFlow;
  //         }
  //       },
  //       {
  //         title: "Duct Name",
  //         render: row => {
  //           return row.settings.ductName;
  //         }
  //       },
  //       {
  //         title: "Duct Length",
  //         render: row => {
  //           return row.settings.ductLength + " m";
  //         }
  //       },
  //       {
  //         title: "Duct Diameter",
  //         render: row => {
  //           return row.settings.ductDiameter + " mm";
  //         }
  //       },
  //       {
  //         title: "Friction Factor",
  //         render: row => {
  //           return row.settings.frictionFactor;
  //         }
  //       },
  //       {
  //         title: "Thermal Conductivity",
  //         render: row => {
  //           return row.settings.thermalConductivity + " W/mK";
  //         }
  //       },
  //       {
  //         title: "Thermal Resistance",
  //         render: row => {
  //           return row.settings.thermalResistance + " K/W";
  //         }
  //       }
  //     ] as Column<Gate>[],
  //     tableSort: new Map([
  //       ["Name", { order: "name", numerical: false }],
  //       ["PCA Type", { order: "pcaType", numerical: false }],
  //       ["Hourly APU Cost", { order: "hourlyApuCost", numerical: true }],
  //       ["Hourly PCA Cost", { order: "hourlyPcaCost", numerical: true }],
  //       ["Upper Flow", { order: "upperFlow", numerical: true }],
  //       ["Lower Flow", { order: "lowerFlow", numerical: true }],
  //       ["Duct Name", { order: "ductName", numerical: false }],
  //       ["Duct Length", { order: "ductLength", numerical: true }],
  //       ["Duct Diameter", { order: "ductDiameter", numerical: true }],
  //       ["Friction Factor", { order: "frictionFactor", numerical: true }],
  //       ["Thermal Conductivity", { order: "thermalConductivity", numerical: true }],
  //       ["Thermal Resistance", { order: "thermalResistance", numerical: true }]
  //     ])
  //   }
  // ],
  [
    pond.ObjectType.OBJECT_TYPE_GRAIN_BAG,
    {
      name: "Grainbag",
      inventoryGroup: "grain",
      isTransactionObject: true,
      tableColumns: [
        {
          title: "Name",
          render: row => {
            if (row.title) {
              return (<div>{row.title.toString()}</div>);
            }
          }
        },
        {
          title: "Length",
          render: row => {
            if (row.settings.length) {
              if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                return row.settings.length.toFixed(2) + " m";
              } else {
                return (row.settings.length * 3.281).toFixed(2) + " ft";
              }
            }
          }
        },
        {
          title: "Diameter",
          render: row => {
            if (row.settings.diameter) {
              if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
                return row.settings.diameter.toFixed(2) + " m";
              } else {
                return (row.settings.diameter * 3.281).toFixed(2) + " ft";
              }
            }
          }
        },
        {
          title: "Grain",
          render: row => {
            if (row.settings.supportedGrain) {
              return GrainDescriber(row.settings.supportedGrain).name;
            }
          }
        },
        {
          title: "Custom Grain",
          render: row => {
            return row.settings.customGrain;
          }
        },
        {
          title: "Grain Variant",
          render: row => {
            return row.settings.grainSubtype;
          }
        },
        {
          title: "Capacity",
          render: row => {
            return row.settings.bushelCapacity + " bu";
          }
        },
        {
          title: "Bushels",
          render: row => {
            return row.settings.currentBushels + " bu";
          }
        },
        {
          title: "Fill Date",
          render: row => {
            return row.settings.fillDate;
          }
        },
        {
          title: "Initial Moisture",
          render: row => {
            return row.settings.initialMoisture + "%";
          }
        }
      ] as Column<GrainBag>[],
      tableSort: new Map([
        ["Name", { order: "name", numerical: false }],
        ["Length", { order: "length", numerical: true }],
        ["Diameter", { order: "diameter", numerical: true }],
        ["Grain", { order: "supportedGrain", numerical: false }],
        ["Custom Grain", { order: "customGrain", numerical: false }],
        ["Grain Variant", { order: "grainSubtype", numerical: false }],
        ["Capacity", { order: "bushelCapacity", numerical: true }],
        ["Bushels", { order: "currentBushels", numerical: true }],
        ["Fill Data", { order: "fillDate", numerical: false }],
        ["Initial Moisture", { order: "initialMoisture", numerical: true }]
      ])
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_GROUP,
    {
      name: "Group",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_HARVESTPLAN,
    {
      name: "Harvest Plan",
      inventoryGroup: "grain",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  // [
  //   pond.ObjectType.OBJECT_TYPE_HEATER,
  //   {
  //     name: "Heater",
  //     inventoryGroup: "",
  //     isTransactionObject: false,
  //     tableColumns: [
  //       {
  //         title: "Name",
  //         render: row => {
  //           if (row.name) {
  //             return row.name.toString();
  //           }
  //         }
  //       },
  //       {
  //         title: "Make",
  //         render: row => {
  //           return row.settings.make;
  //         }
  //       },
  //       {
  //         title: "Model",
  //         render: row => {
  //           return row.settings.model;
  //         }
  //       },
  //       {
  //         title: "Fuel Type",
  //         render: row => {
  //           let fuelMap = new Map<pond.FuelType, string>([
  //             [pond.FuelType.FUEL_TYPE_DIESEL, "Diesel"],
  //             [pond.FuelType.FUEL_TYPE_GASOLINE, "Gasoline"],
  //             [pond.FuelType.FUEL_TYPE_PROPANE, "Propane"]
  //           ]);
  //           return fuelMap.get(row.settings.fuelType);
  //         }
  //       },
  //       {
  //         title: "Tank Size",
  //         render: row => {
  //           return row.settings.tankSize + " G";
  //         }
  //       },
  //       {
  //         title: "Fuel Consumption",
  //         render: row => {
  //           return row.settings.fuelConsumption + " G/hr";
  //         }
  //       },
  //       {
  //         title: "Air Circulation",
  //         render: row => {
  //           return row.settings.airCirculation + " CFM";
  //         }
  //       }
  //     ] as Column<ObjectHeater>[],
  //     tableSort: new Map([
  //       ["Name", { order: "name", numerical: false }],
  //       ["Make", { order: "make", numerical: false }],
  //       ["Model", { order: "model", numerical: false }],
  //       ["Fuel Type", { order: "fuelType", numerical: false }],
  //       ["Tank Size", { order: "tankSize", numerical: true }],
  //       ["Fuel Consumption", { order: "fuelConsumption", numerical: true }],
  //       ["Air Circulation", { order: "airCirculation", numerical: true }]
  //     ])
  //   }
  // ],
  [
    pond.ObjectType.OBJECT_TYPE_HOMEMARKER,
    {
      name: "Home Marker",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_INTERACTION,
    {
      name: "Interaction",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_LINK,
    {
      name: "Link",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_MINE,
    {
      name: "Mine",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_NOTE,
    {
      name: "Note",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_SITE,
    {
      name: "Site",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_TAG,
    {
      name: "Tag",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_TASK,
    {
      name: "Task",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_TEAM,
    {
      name: "Team",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_TERMINAL,
    {
      name: "Terminal",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_UPGRADE,
    {
      name: "Upgrade",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_USER,
    {
      name: "User",
      inventoryGroup: "",
      isTransactionObject: false,
      tableColumns: [],
      tableSort: new Map()
    }
  ],
  [
    pond.ObjectType.OBJECT_TYPE_CONTRACT,
    {
      name: "Contract",
      inventoryGroup: "grain",
      isTransactionObject: true,
      tableColumns: [],
      tableSort: new Map()
    }
  ]
]);

export default function ObjectDescriber(type: pond.ObjectType): ObjectExtension {
  let describer = ObjectExtensions.get(type);
  return describer ? describer : defaultObject;
}

/**
 * takes in an object type enum and returns the string of that object type that is used in the relative_objects table
 * ie "Bin" -> "bin" or "Home Marker" -> "home_marker"
 * @param type pond.ObjectType enum
 */
export function ObjectTypeString(type: pond.ObjectType): string {
  return ObjectDescriber(type)
    .name.toLocaleLowerCase()
    .replace(/ /g, "_");
}

export function TransactionOptions(): Option[] {
  let options: Option[] = [];
  Object.values(pond.ObjectType).forEach(obj => {
    if (typeof obj !== "string") {
      let ext = ObjectDescriber(obj);
      if (ext.isTransactionObject) {
        options.push({
          label: ext.name,
          value: obj,
          group: ext.inventoryGroup
        });
      }
    }
  });
  return options;
}

export function SearchableObjects(): Option[] {
  let options: Option[] = [];
  Object.values(pond.ObjectType).forEach(obj => {
    if (typeof obj !== "string") {
      let ext = ObjectDescriber(obj);
      if (ext.tableColumns.length > 0) {
        options.push({
          label: ext.name,
          value: obj
        });
      }
    }
  });
  return options;
}
