"use client";

import { Button, Input, Segmented, Select, Switch, Typography } from "antd";
import { DeleteOutlined, PlusOutlined } from "@ant-design/icons";
import { useEffect, useState } from "react";
import { COUNTRY_OPTIONS } from "@/lib/utils/countries";
import {
  FIELD_DEFINITIONS,
  OPERATOR_LABELS,
  buildExpression,
  emptyCondition,
  isValidOperator,
} from "@/lib/utils/cfExpression";
import type { Condition, FieldKey, OperatorKey } from "@/lib/utils/cfExpression";

const METHOD_OPTIONS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"].map((m) => ({ value: m, label: m }));

function ValueInput({ condition, onChange }: { condition: Condition; onChange: (values: string[]) => void }) {
  const kind = FIELD_DEFINITIONS[condition.field].kind;
  const isList = condition.operator === "in" || condition.operator === "not_in";

  if (kind === "country") {
    return (
      <Select
        mode={isList ? "multiple" : undefined}
        showSearch
        optionFilterProp="label"
        placeholder={isList ? "Pick countries" : "Pick a country"}
        value={isList ? condition.values : (condition.values[0] ?? undefined)}
        options={COUNTRY_OPTIONS}
        onChange={(v) => onChange(Array.isArray(v) ? v : v ? [v] : [])}
        style={{ width: "100%" }}
      />
    );
  }

  if (kind === "method") {
    return (
      <Select
        mode={isList ? "multiple" : undefined}
        placeholder="Method"
        value={isList ? condition.values : (condition.values[0] ?? undefined)}
        options={METHOD_OPTIONS}
        onChange={(v) => onChange(Array.isArray(v) ? v : v ? [v] : [])}
        style={{ width: "100%" }}
      />
    );
  }

  if (isList) {
    return (
      <Select
        mode="tags"
        tokenSeparators={[",", " "]}
        placeholder={kind === "ip" ? "203.0.113.10, 198.51.100.0/24" : "Type a value, press Enter"}
        value={condition.values}
        onChange={(v) => onChange(v)}
        open={false}
        style={{ width: "100%" }}
      />
    );
  }

  return (
    <Input
      placeholder={kind === "ip" ? "203.0.113.10 or 203.0.113.0/24" : kind === "number" ? "13335" : "Value"}
      value={condition.values[0] ?? ""}
      onChange={(e) => onChange(e.target.value ? [e.target.value] : [])}
    />
  );
}

/**
 * Builds a Cloudflare rule expression from conditions instead of making the
 * operator hand-write the syntax: pick a field, an operator and a value per
 * row, and join the rows with AND / OR (AND binds tighter, as in Cloudflare).
 * The finished expression is shown live and handed to the form as a string;
 * "Write it myself" swaps the builder for a plain text box for anything the
 * builder does not cover.
 */
export function ExpressionBuilder({
  value,
  onChange,
}: {
  value?: string;
  onChange?: (expression: string) => void;
}) {
  const [conditions, setConditions] = useState<Condition[]>([emptyCondition()]);
  const [isManual, setIsManual] = useState(false);
  const expression = buildExpression(conditions);

  useEffect(() => {
    if (!isManual) onChange?.(expression ?? "");
    // onChange identity changes with the parent form's render - only a change
    // in the built expression should be reported.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [expression, isManual]);

  function update(index: number, patch: Partial<Condition>) {
    setConditions((current) => current.map((c, i) => (i === index ? { ...c, ...patch } : c)));
  }

  function changeField(index: number, field: FieldKey) {
    setConditions((current) =>
      current.map((c, i) => (i === index ? { ...emptyCondition(field), join: c.join } : c)),
    );
  }

  function changeOperator(index: number, operator: OperatorKey) {
    setConditions((current) =>
      current.map((c, i) => {
        if (i !== index || !isValidOperator(c.field, operator)) return c;
        const wasList = c.operator === "in" || c.operator === "not_in";
        const isList = operator === "in" || operator === "not_in";

        return { ...c, operator, values: wasList === isList ? c.values : c.values.slice(0, 1) };
      }),
    );
  }

  return (
    <div className="flex flex-col gap-2 dms_expression_builder">
      <div className="flex items-center justify-between">
        <Typography.Text type="secondary" className="text-xs">
          {isManual ? "Write the expression yourself." : "Add conditions; join them with AND / OR."}
        </Typography.Text>
        <span className="flex items-center gap-2 text-xs">
          Write it myself
          <Switch
            size="small"
            checked={isManual}
            onChange={(checked) => {
              setIsManual(checked);
              if (checked) onChange?.(expression ?? value ?? "");
            }}
            className="dms_expression_builder_manual_switch"
          />
        </span>
      </div>

      {isManual ? (
        <Input.TextArea
          rows={3}
          className="font-mono"
          placeholder='(ip.geoip.country eq "CN") or (http.request.uri.path contains "/admin")'
          value={value}
          onChange={(e) => onChange?.(e.target.value)}
        />
      ) : (
        <>
          {conditions.map((condition, index) => (
            <div key={index} className="flex flex-col gap-1">
              <div className="grid gap-2 dms_expression_row" style={{ gridTemplateColumns: "170px 170px 1fr 32px" }}>
                <Select<FieldKey>
                  value={condition.field}
                  onChange={(field) => changeField(index, field)}
                  options={(Object.keys(FIELD_DEFINITIONS) as FieldKey[]).map((f) => ({ value: f, label: FIELD_DEFINITIONS[f].label }))}
                />
                <Select<OperatorKey>
                  value={condition.operator}
                  onChange={(operator) => changeOperator(index, operator)}
                  options={FIELD_DEFINITIONS[condition.field].operators.map((o) => ({ value: o, label: OPERATOR_LABELS[o] }))}
                />
                <ValueInput condition={condition} onChange={(values) => update(index, { values })} />
                <Button
                  icon={<DeleteOutlined />}
                  disabled={conditions.length === 1}
                  onClick={() => setConditions((current) => current.filter((_, i) => i !== index))}
                  aria-label="Remove condition"
                  className="dms_expression_remove_btn"
                />
              </div>
              {index < conditions.length - 1 && (
                <Segmented<"and" | "or">
                  size="small"
                  value={condition.join}
                  options={[
                    { value: "and", label: "AND" },
                    { value: "or", label: "OR" },
                  ]}
                  onChange={(join) => update(index, { join })}
                  className="self-start dms_expression_join"
                />
              )}
            </div>
          ))}
          <Button
            size="small"
            icon={<PlusOutlined />}
            onClick={() => setConditions((current) => [...current, emptyCondition()])}
            className="self-start dms_expression_add_btn"
          >
            Add condition
          </Button>
          <div className="rounded px-3 py-2 font-mono text-xs break-all dms_expression_preview" style={{ background: "rgba(128,128,128,0.12)" }}>
            {expression ?? "Fill in every condition to see the expression."}
          </div>
        </>
      )}
    </div>
  );
}
