import { APIUrl } from "@/src/database/database";
import { SelectRequestBody, TableConditionGroups, TableJoin } from "./DataStructure";
import { DataStructure, SchemaOptions } from "./DataStructure";
import {  RefObject, useEffect, useState } from "react";
import axios from "axios";
import Select from "react-select";
import makeAnimated from 'react-select/animated';
import { Button } from "./Button";
import { useRouter } from "next/navigation";
import { format } from "date-fns";

const countries: { value: string; label: string }[] = [
  { value: "Afghanistan", label: "Afghanistan" },
  { value: "Albania", label: "Albania" },
  { value: "Algeria", label: "Algeria" },
  { value: "Andorra", label: "Andorra" },
  { value: "Angola", label: "Angola" },
  { value: "Antigua and Barbuda", label: "Antigua and Barbuda" },
  { value: "Argentina", label: "Argentina" },
  { value: "Armenia", label: "Armenia" },
  { value: "Australia", label: "Australia" },
  { value: "Austria", label: "Austria" },
  { value: "Azerbaijan", label: "Azerbaijan" },
  { value: "Bahamas", label: "Bahamas" },
  { value: "Bahrain", label: "Bahrain" },
  { value: "Bangladesh", label: "Bangladesh" },
  { value: "Barbados", label: "Barbados" },
  { value: "Belarus", label: "Belarus" },
  { value: "Belgium", label: "Belgium" },
  { value: "Belize", label: "Belize" },
  { value: "Benin", label: "Benin" },
  { value: "Bhutan", label: "Bhutan" },
  { value: "Bolivia", label: "Bolivia" },
  { value: "Bosnia and Herzegovina", label: "Bosnia and Herzegovina" },
  { value: "Botswana", label: "Botswana" },
  { value: "Brazil", label: "Brazil" },
  { value: "Brunei", label: "Brunei" },
  { value: "Bulgaria", label: "Bulgaria" },
  { value: "Burkina Faso", label: "Burkina Faso" },
  { value: "Burundi", label: "Burundi" },
  { value: "Cabo Verde", label: "Cabo Verde" },
  { value: "Cambodia", label: "Cambodia" },
  { value: "Cameroon", label: "Cameroon" },
  { value: "Canada", label: "Canada" },
  { value: "Central African Republic", label: "Central African Republic" },
  { value: "Chad", label: "Chad" },
  { value: "Chile", label: "Chile" },
  { value: "China", label: "China" },
  { value: "Colombia", label: "Colombia" },
  { value: "Comoros", label: "Comoros" },
  { value: "Congo, Democratic Republic of the", label: "Congo, Democratic Republic of the" },
  { value: "Congo, Republic of the", label: "Congo, Republic of the" },
  { value: "Costa Rica", label: "Costa Rica" },
  { value: "Croatia", label: "Croatia" },
  { value: "Cuba", label: "Cuba" },
  { value: "Cyprus", label: "Cyprus" },
  { value: "Czech Republic", label: "Czech Republic" },
  { value: "Denmark", label: "Denmark" },
  { value: "Djibouti", label: "Djibouti" },
  { value: "Dominica", label: "Dominica" },
  { value: "Dominican Republic", label: "Dominican Republic" },
  { value: "Ecuador", label: "Ecuador" },
  { value: "Egypt", label: "Egypt" },
  { value: "El Salvador", label: "El Salvador" },
  { value: "Equatorial Guinea", label: "Equatorial Guinea" },
  { value: "Eritrea", label: "Eritrea" },
  { value: "Estonia", label: "Estonia" },
  { value: "Eswatini", label: "Eswatini" },
  { value: "Ethiopia", label: "Ethiopia" },
  { value: "Fiji", label: "Fiji" },
  { value: "Finland", label: "Finland" },
  { value: "France", label: "France" },
  { value: "Gabon", label: "Gabon" },
  { value: "Gambia", label: "Gambia" },
  { value: "Georgia", label: "Georgia" },
  { value: "Germany", label: "Germany" },
  { value: "Ghana", label: "Ghana" },
  { value: "Greece", label: "Greece" },
  { value: "Grenada", label: "Grenada" },
  { value: "Guatemala", label: "Guatemala" },
  { value: "Guinea", label: "Guinea" },
  { value: "Guinea-Bissau", label: "Guinea-Bissau" },
  { value: "Guyana", label: "Guyana" },
  { value: "Haiti", label: "Haiti" },
  { value: "Honduras", label: "Honduras" },
  { value: "Hungary", label: "Hungary" },
  { value: "Iceland", label: "Iceland" },
  { value: "India", label: "India" },
  { value: "Indonesia", label: "Indonesia" },
  { value: "Iran", label: "Iran" },
  { value: "Iraq", label: "Iraq" },
  { value: "Ireland", label: "Ireland" },
  { value: "Israel", label: "Israel" },
  { value: "Italy", label: "Italy" },
  { value: "Jamaica", label: "Jamaica" },
  { value: "Japan", label: "Japan" },
  { value: "Jordan", label: "Jordan" },
  { value: "Kazakhstan", label: "Kazakhstan" },
  { value: "Kenya", label: "Kenya" },
  { value: "Kiribati", label: "Kiribati" },
  { value: "Korea, North", label: "Korea, North" },
  { value: "Korea, South", label: "Korea, South" },
  { value: "Kosovo", label: "Kosovo" },
  { value: "Kuwait", label: "Kuwait" },
  { value: "Kyrgyzstan", label: "Kyrgyzstan" },
  { value: "Laos", label: "Laos" },
  { value: "Latvia", label: "Latvia" },
  { value: "Lebanon", label: "Lebanon" },
  { value: "Lesotho", label: "Lesotho" },
  { value: "Liberia", label: "Liberia" },
  { value: "Libya", label: "Libya" },
  { value: "Liechtenstein", label: "Liechtenstein" },
  { value: "Lithuania", label: "Lithuania" },
  { value: "Luxembourg", label: "Luxembourg" },
  { value: "Madagascar", label: "Madagascar" },
  { value: "Malawi", label: "Malawi" },
  { value: "Malaysia", label: "Malaysia" },
  { value: "Maldives", label: "Maldives" },
  { value: "Mali", label: "Mali" },
  { value: "Malta", label: "Malta" },
  { value: "Marshall Islands", label: "Marshall Islands" },
  { value: "Mauritania", label: "Mauritania" },
  { value: "Mauritius", label: "Mauritius" },
  { value: "Mexico", label: "Mexico" },
  { value: "Micronesia", label: "Micronesia" },
  { value: "Moldova", label: "Moldova" },
  { value: "Monaco", label: "Monaco" },
  { value: "Mongolia", label: "Mongolia" },
  { value: "Montenegro", label: "Montenegro" },
  { value: "Morocco", label: "Morocco" },
  { value: "Mozambique", label: "Mozambique" },
  { value: "Myanmar", label: "Myanmar" },
  { value: "Namibia", label: "Namibia" },
  { value: "Nauru", label: "Nauru" },
  { value: "Nepal", label: "Nepal" },
  { value: "Netherlands", label: "Netherlands" },
  { value: "New Zealand", label: "New Zealand" },
  { value: "Nicaragua", label: "Nicaragua" },
  { value: "Niger", label: "Niger" },
  { value: "Nigeria", label: "Nigeria" },
  { value: "North Macedonia", label: "North Macedonia" },
  { value: "Norway", label: "Norway" },
  { value: "Oman", label: "Oman" },
  { value: "Pakistan", label: "Pakistan" },
  { value: "Palau", label: "Palau" },
  { value: "Panama", label: "Panama" },
  { value: "Papua New Guinea", label: "Papua New Guinea" },
  { value: "Paraguay", label: "Paraguay" },
  { value: "Peru", label: "Peru" },
  { value: "Philippines", label: "Philippines" },
  { value: "Poland", label: "Poland" },
  { value: "Portugal", label: "Portugal" },
  { value: "Qatar", label: "Qatar" },
  { value: "Romania", label: "Romania" },
  { value: "Russia", label: "Russia" },
  { value: "Rwanda", label: "Rwanda" },
  { value: "Saint Kitts and Nevis", label: "Saint Kitts and Nevis" },
  { value: "Saint Lucia", label: "Saint Lucia" },
  { value: "Saint Vincent and the Grenadines", label: "Saint Vincent and the Grenadines" },
  { value: "Samoa", label: "Samoa" },
  { value: "San Marino", label: "San Marino" },
  { value: "Sao Tome and Principe", label: "Sao Tome and Principe" },
  { value: "Saudi Arabia", label: "Saudi Arabia" },
  { value: "Senegal", label: "Senegal" },
  { value: "Serbia", label: "Serbia" },
  { value: "Seychelles", label: "Seychelles" },
  { value: "Sierra Leone", label: "Sierra Leone" },
  { value: "Singapore", label: "Singapore" },
  { value: "Slovakia", label: "Slovakia" },
  { value: "Slovenia", label: "Slovenia" },
  { value: "Solomon Islands", label: "Solomon Islands" },
  { value: "Somalia", label: "Somalia" },
  { value: "South Africa", label: "South Africa" },
  { value: "South Sudan", label: "South Sudan" },
  { value: "Spain", label: "Spain" },
  { value: "Sri Lanka", label: "Sri Lanka" },
  { value: "Sudan", label: "Sudan" },
  { value: "Suriname", label: "Suriname" },
  { value: "Sweden", label: "Sweden" },
  { value: "Switzerland", label: "Switzerland" },
  { value: "Syria", label: "Syria" },
  { value: "Taiwan", label: "Taiwan" },
  { value: "Tajikistan", label: "Tajikistan" },
  { value: "Tanzania", label: "Tanzania" },
  { value: "Thailand", label: "Thailand" },
  { value: "Timor-Leste", label: "Timor-Leste" },
  { value: "Togo", label: "Togo" },
  { value: "Tonga", label: "Tonga" },
  { value: "Trinidad and Tobago", label: "Trinidad and Tobago" },
  { value: "Tunisia", label: "Tunisia" },
  { value: "Turkey", label: "Turkey" },
  { value: "Turkmenistan", label: "Turkmenistan" },
  { value: "Tuvalu", label: "Tuvalu" },
  { value: "Uganda", label: "Uganda" },
  { value: "Ukraine", label: "Ukraine" },
  { value: "United Arab Emirates", label: "United Arab Emirates" },
  { value: "United Kingdom", label: "United Kingdom" },
  { value: "United States", label: "United States" },
  { value: "Uruguay", label: "Uruguay" },
  { value: "Uzbekistan", label: "Uzbekistan" },
  { value: "Vanuatu", label: "Vanuatu" },
  { value: "Vatican City", label: "Vatican City" },
  { value: "Venezuela", label: "Venezuela" },
  { value: "Vietnam", label: "Vietnam" },
  { value: "Yemen", label: "Yemen" },
  { value: "Zambia", label: "Zambia" },
  { value: "Zimbabwe", label: "Zimbabwe" }
];

const yesNoOptions = [{
  value: "Yes",
  label: "Yes"
}, {
  value: "No",
  label: "No"
}]

interface Props{
  dataStructure: DataStructure;
  assetEndpointURL?: string;
  inputRef?: RefObject<any>;
  colspan?: 2;
  className?: string;
  hideLabel?: boolean;
  placeholder?: string;
  value?: string;
  hidden?: boolean;
  onChange?: (inputValue: any) => void;
}

const animatedComponents = makeAnimated();

export const DataField = (props: Props) => {

  const [selectOptions, setSelectOptions] = useState<SchemaOptions[]>([]);
  const [inputValue, setInputValue] = useState<any>();
  const router = useRouter();

  useEffect(() => {
    if(props.value !== undefined && props.value !== null){
      
      if(props.dataStructure.fieldId == "country"){
        const localOption: SchemaOptions = {
          value: countries.filter((eachCountry) => eachCountry.value === props.value).length > 0 ? countries.filter((eachCountry) => eachCountry.value === props.value)[0].value : "",
          label: countries.filter((eachCountry) => eachCountry.value === props.value).length > 0 ? countries.filter((eachCountry) => eachCountry.value === props.value)[0].label : "",
        };
        setInputValue(localOption);
      }else if(props.dataStructure.options && props.dataStructure.options.length > 0){
        const localOption = props.dataStructure.options.filter((eachOption) => eachOption.value == props.value);
        if(localOption){
          setInputValue(localOption);
        }
      }
      else if(
        props.dataStructure.type != "reference"
      ){
        setInputValue(props.value);
      }
    }else{
      setInputValue(undefined);
    }
  }, [props.value]);

  useEffect(() => {
    if(props.onChange){
      props.onChange(inputValue);
    }
  }, [inputValue]);

  useEffect(() => {
    if(props.dataStructure.type == "reference" || props.dataStructure.type == "multiReference")
      handleReferenceData();
    else if(props.dataStructure.type == "multiValue")
      handleMultiValueData();
  }, [props.dataStructure, props.value]);

  const handleMultiValueData = async () => {
    const formData = new FormData();
    const columns: string[] = [
      "id",
      props.dataStructure.referenceDisplay ?? ""
    ];
    if(props.dataStructure.referenceValueTypeColumn){
      columns.push(props.dataStructure.referenceValueTypeColumn);
    }

    const selectQuery: SelectRequestBody = {
      table: props.dataStructure.referenceId ?? "",
      columns,
      limit: 1000,
    }
    formData.append("query", JSON.stringify(selectQuery));

    try{
      const queryRes = await axios.post(`${APIUrl}/api/select`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });

      if(queryRes.data && queryRes.data["rows"]){
        const localOptions: SchemaOptions[] = [];
        queryRes.data["rows"].map((eachData: any) => {
          let options: SchemaOptions[] = [];
          if(props.dataStructure.referenceValueTypeColumn && !Number(eachData[props.dataStructure.referenceValueTypeColumn])){
            eachData[props.dataStructure.referenceValueTypeColumn].split(',').map((pair) => {
              const [value, label] = pair.split('|');
                options.push({
                  value,
                  label
                })
              return null;
            });
          }

          const localOption: SchemaOptions = {
            value: eachData['id'],
            label: eachData[props.dataStructure.referenceDisplay ?? ""],
            valueType: props.dataStructure.referenceValueTypeColumn ? eachData[props.dataStructure.referenceValueTypeColumn] : null,
            options: options.length > 0 ? options : undefined,
          };

          localOptions.push(localOption);
        });
        setSelectOptions(localOptions);
      }
    }catch(err) {
      console.log(err);
    }
  }

  const handleReferenceData = async () => {
    const formData = new FormData();
    const selectQuery: SelectRequestBody = {
      table: props.dataStructure.referenceId ?? "",
      columns: [
        "id",
        props.dataStructure.referenceDisplay ?? ""
      ],
      limit: -1
    }
    formData.append("query", JSON.stringify(selectQuery));

    try{
      const queryRes = await axios.post(`${APIUrl}/api/select`, formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });

      if(queryRes.data && queryRes.data["rows"]){
        const localOptions: SchemaOptions[] = [];
        queryRes.data["rows"].map((eachData: any) => {

          let label = eachData[props.dataStructure.referenceDisplay ?? ""];

          if(props.dataStructure.referenceDisplayIsDate){
            label = format(label, 'yyyy-MM-dd');
          }else if(props.dataStructure.referenceDisplayIsTime){
            label = format(label, 'yyyy-MM-dd HH:mm:ss');
          }

          const localOption: SchemaOptions = {
            value: eachData['id'],
            label: eachData[props.dataStructure.referenceDisplay ?? ""]
          };

          localOptions.push(localOption);
          if(eachData['id'] == props.value){
            setInputValue(localOption);
          }
        });
        setSelectOptions(localOptions);
      }
    }catch(err) {
      console.log(err);
    }
  };

  const renderClassName = () => {
    let colspan = "";
    switch(props.colspan){
      case 2: 
        colspan = "col-span-2"
        break;
      default:
        colspan = "sm:col-auto col-span-2"
        if(props.dataStructure.type === "multiValue"){
          colspan = "col-span-2"
        }
    }

    if(props.hidden) colspan += " hidden";

    return `${colspan} ${props.className ?? ""}`;
  }

  const renderRequired = () => {
    if(!props.dataStructure.required)
      return "";

    return <span className="text-red-500">*</span>
  }

  const renderField = () => {
    switch(props.dataStructure.type){
      case "reference":
      case "multiReference":
        return (selectOptions.length > 0 && (
          <Select
            closeMenuOnSelect={props.dataStructure.type !== "multiReference"}
            components={animatedComponents}
            isMulti={props.dataStructure.type === "multiReference"}
            options={selectOptions}
            onChange={(newValue: any) => {
              setInputValue(newValue);
            }}
            value={inputValue}
          />
        ))
      case "string":
        return (props.dataStructure.fieldId !== "country" ? (
          <input 
            type={"text"}
            id={props.dataStructure.fieldId}
            className="py-2 px-5 w-full border-2 border-slate-200 rounded-md"
            onChange={(e) => {
              setInputValue(e.target.value);
            }}
            placeholder={props.placeholder}
            ref={props.inputRef}
            value={inputValue}
          />
        ) : (
          <Select
            id={props.dataStructure.fieldId}
            closeMenuOnSelect={true}
            components={animatedComponents}
            onChange={(newValue: any) => {
              setInputValue(newValue);
            }}
            value={inputValue}
            options={countries}
          />
        ))
      case "file":
        return (
          <>
            <input 
              type="file"
              id={props.dataStructure.fieldId}
              className="py-2 px-5 w-full border-2 border-slate-200 rounded-md"
              onChange={(e) => {
                if(e.target.files && e.target.files.length > 0){
                  setInputValue(e.target.files[0]);
                }
              }}
              placeholder={props.placeholder}
              ref={props.inputRef}
            />
            {inputValue && <Button
              text={`Preview ${typeof inputValue !== "string" ? inputValue.name : inputValue}`}
              additionalClassName="!p-0 text-center"
              bgColor="bg-transparent"
              color="text-primary-400 hover:text-neutral-400"
              size="sm"
              onClick={() => {
                window.open(typeof inputValue !== "string" ? URL.createObjectURL(inputValue) : `${props.assetEndpointURL}/${inputValue}`)
              }}
            />}
          </>
        )
      case "number":
      case "date":
      case "password":
      case "datetime-local":
        return (!props.dataStructure.options || props.dataStructure.options.length < 1 ? (
          <input 
            type={props.dataStructure.type}
            id={props.dataStructure.fieldId}
            className="py-2 px-5 w-full border-2 border-slate-200 rounded-md"
              onChange={(e) => {
                setInputValue(e.target.value);
              }}
            placeholder={props.placeholder}
            ref={props.inputRef}
            value={inputValue}
          />
        ) : (
          <Select
            closeMenuOnSelect
            components={animatedComponents}
            options={props.dataStructure.options}
            onChange={(newValue: any) => {
              setInputValue(newValue);
            }}
            value={inputValue}
          />
        ))
    }
  }

  const renderMultiValueField = () => {
    return (selectOptions.length > 0 && (
      <div className={`${renderClassName()} col-span-2 pt-4 border-t-2 mt-4`} ref={props.inputRef}>
        <h2 className="text-xl font-medium text-gray-800">{props.dataStructure.displayName}</h2>
        {props.dataStructure.hint && <p className="text-gray-500 mb-4 text-sm">{props.dataStructure.hint}</p>}
        <div className="grid gap-4 md:grid-cols-2 grid-cols-1">
          {selectOptions.length > 0 && selectOptions.map((eachOption, index) => {
            return (
              <div key={index}>
                {!props.hideLabel && <label htmlFor={eachOption.value}>{eachOption.label} {renderRequired()}</label>}
                {eachOption.valueType && eachOption.valueType !== 3 ? (
                  <>
                    {!eachOption.options ? (
                      <input 
                        type={eachOption.valueType && eachOption.valueType === 2 ? "number" : "text"}
                        id={eachOption.value}
                        className="py-2 px-5 w-full border-2 border-slate-200 rounded-md"
                        onChange={(e) => {
                          const localValue = {...inputValue};
                          localValue[eachOption.value] = {
                            label: eachOption.label,
                            value: e.target.value
                          }
                          setInputValue(localValue);
                        }}
                        placeholder={props.placeholder}
                        value={inputValue ? inputValue[eachOption.value]?.value : undefined}
                      />
                    ) : (
                      <Select
                        closeMenuOnSelect={true}
                        components={animatedComponents}
                        options={eachOption.options}
                        onChange={(newValue: any) => {
                          const localValue = {...inputValue};
                          localValue[eachOption.value] = newValue
                          setInputValue(localValue);
                        }}
                      />
                    )}
                  </>
                ): (
                  <Select
                    closeMenuOnSelect={true}
                    components={animatedComponents}
                    options={yesNoOptions}
                    onChange={(newValue: any) => {
                      const localValue = {...inputValue};
                      localValue[eachOption.value] = newValue
                      setInputValue(localValue);
                    }}
                    value={(inputValue && inputValue[eachOption.value]) ?
                      (
                        inputValue[eachOption.value].value === "Yes" ? yesNoOptions[0] : yesNoOptions[1]
                      )
                      : undefined}
                  />
                )}
              </div>
            )
          })}
        </div>
      </div>
    ))
  }

  return(
    <>
      {props.dataStructure.type === "multiValue" ? (
        <>
          {renderMultiValueField()}
        </>
      ) : (
        <div className={renderClassName()}>
          {!props.hideLabel && <label htmlFor={props.dataStructure.fieldId}>{props.dataStructure.displayName} {renderRequired()}</label>}
          {renderField()}
          {props.dataStructure.hint && <p className="text-gray-500 text-sm">* {props.dataStructure.hint}</p>}
        </div>
      )}
    </>
  )
}