import React, { useEffect, useState } from "react";
import { SelectRuleBlock } from "../RuleBlocks";
import { NumericComparisonBlock } from "../RuleBlocks/NumericComparisonBlock";

import { SelectOption, CommonSelectOptions } from "../../types/select";

import { anySelectionValues } from "../../constants/segments/attributes";

import {
  SegmentAttribute,
  SegmentExpression,
  SegmentPropertyAttribute,
  SegmentValue,
} from "@komi-app/fans-sdk";

import When from "@komi-app/when";

import { findValuesInOptions, valuesToOptions } from "../../utils/select";
import { getAttributeByName } from "../../utils/attributes";

import classnames from "classnames";
import "./RuleClause.scss";
import { DateRangeBlock as DateRangeBlockOld } from "../RuleBlocks/DateRangeBlock/DateRangeBlock.old";
import { DateRangeBlock as DateRangeBlockNew } from "../RuleBlocks/DateRangeBlock/DateRangeBlock.new";
import DefaultClause from "./DefaultRuleClause";
import { FLAGS, useFeatureIsOn } from "@komi-app/flags-sdk";

export interface SegmentClauseProperty {
  name: string;
  getValues: () => Promise<string[]>;
}

export interface RuleClauseProps extends React.HTMLProps<HTMLDivElement> {
  expression: SegmentExpression;
  properties: SegmentAttribute[];
  selectedExpressions: SegmentAttribute[];
  onExpressionChange: (expression: SegmentExpression) => void;
  segmentPropertyAttributes: SegmentPropertyAttribute[];
}
export const RuleClause: React.FC<RuleClauseProps> = ({
  expression,
  properties,
  selectedExpressions = [],
  onExpressionChange,
  segmentPropertyAttributes,
  ...props
}) => {
  const { attributeName, inverted, attributeValues = [] } = expression;

  const attribute = getAttributeByName(
    attributeName,
    segmentPropertyAttributes,
  );

  const propNameOptions = properties.map<SelectOption>(({ name }) => ({
    label: name,
    value: name,
  }));

  const [propValueOptions, setPropValueOptions] = useState<SelectOption[]>([]);

  const selectedPropValueOptions = attributeValues.includes(
    CommonSelectOptions.Any,
  )
    ? propValueOptions
    : findValuesInOptions(attributeValues, propValueOptions);

  const [isOptionsLoading, setIsOptionsLoading] = useState(false);

  // Fetch the corresponding attribute values on name change
  useEffect(() => {
    const fetchPropertyValues = async () => {
      // If there's an attribute selected whose value is that of a property
      const property = properties.find((property) => {
        return property.name === attributeName;
      });
      if (!property) {
        return;
      }

      setIsOptionsLoading(true);
      const options: SelectOption[] = [];

      if (property.getValues) {
        const values = await property.getValues();
        const propOptions = valuesToOptions(values);
        options.push(...propOptions);
      } else if (property.getOptions) {
        const propOptions = await property.getOptions();
        options.push(...propOptions);
      }

      setIsOptionsLoading(false);
      setPropValueOptions(options);
    };

    fetchPropertyValues();
  }, [attributeName]);

  const handleAttributeNameChange = async ([attributeName]: string[]) => {
    const attribute = getAttributeByName(
      attributeName,
      segmentPropertyAttributes,
    );
    const { defaultValues = [] } = attribute;

    const updatedExpression = {
      ...expression,
      attributeName,
      attributeValues: defaultValues,
    };
    onExpressionChange(updatedExpression);
  };
  const handleSqlInvertedChange = (inverted: boolean) => {
    const updatedExpression = { ...expression, inverted };
    onExpressionChange(updatedExpression);
  };
  const handleOptionSelectionChange = (selectedOptions: SelectOption[]) => {
    const attributeValues =
      selectedOptions.length === propValueOptions.length
        ? anySelectionValues
        : selectedOptions.map(({ value }) => value);

    const updatedExpression = { ...expression, attributeValues };

    onExpressionChange(updatedExpression);
  };

  const classNames = classnames("rule-clause", props.className);

  return (
    <div {...props} className={classNames}>
      <SelectRuleBlock
        className="rule-clause__attribute-name"
        selectedValues={attributeName}
        disabledValues={selectedExpressions.map(({ name }) => name)}
        options={propNameOptions}
        onValueSelectionChange={handleAttributeNameChange}
      />

      <When
        value={attribute.valueType}
        then={{
          [SegmentValue.Number]: (
            <NumericComparisonBlock
              className="rule-clause__attribute-value"
              expression={expression}
              onExpressionChange={onExpressionChange}
              segmentPropertyAttributes={segmentPropertyAttributes}
            />
          ),
          [SegmentValue.DateRange]: (
            <DateRangeBlockNew
              className="rule-clause__attribute-value"
              expression={expression}
              onExpressionChange={onExpressionChange}
              segmentPropertyAttributes={segmentPropertyAttributes}
            />
          ),
        }}
        otherwise={
          <DefaultClause
            inverted={inverted}
            onInvertedChange={handleSqlInvertedChange}
            options={propValueOptions}
            selectedOptions={selectedPropValueOptions}
            isLoading={isOptionsLoading}
            onOptionsChange={handleOptionSelectionChange}
            attributeName={attribute?.name}
          />
        }
      />
    </div>
  );
};
