"use client";

import { useEffect, useRef, useState } from "react";
import { PhoneNumberFormat, PhoneNumberUtil } from "google-libphonenumber";
import type { QuestionField } from "@/data/question-data";
import type { MarriagePhoneFieldValue } from "@/hooks/marriage/types";
import { useQuestionAnswer } from "./question-answer-storage";
import QuestionTitle from "./question-title";

type QuestionPhoneProps = {
  question: QuestionField;
  questionIndex: number;
  countryCode?: string;
};

type PhoneValueParts = {
  codeValue: string;
  phoneValue: string;
};

const phoneUtil = PhoneNumberUtil.getInstance();

function isMarriagePhoneFieldValue(
  value: unknown,
): value is MarriagePhoneFieldValue {
  if (!value || typeof value !== "object") {
    return false;
  }

  const phoneValue = value as Partial<MarriagePhoneFieldValue>;

  return (
    typeof phoneValue.countryCode === "string" &&
    typeof phoneValue.phoneNumber === "string"
  );
}

function readPhoneValue(value: unknown, fallbackCode: string): PhoneValueParts {
  if (value === null) {
    return {
      codeValue: "",
      phoneValue: "",
    };
  }

  if (isMarriagePhoneFieldValue(value)) {
    return {
      codeValue: value.countryCode
        ? `+${value.countryCode.replace(/^\+/, "")}`
        : fallbackCode,
      phoneValue: value.phoneNumber,
    };
  }

  if (typeof value !== "string") {
    return {
      codeValue: fallbackCode,
      phoneValue: "",
    };
  }

  if (value.length === 0) {
    return {
      codeValue: "",
      phoneValue: "",
    };
  }

  const separatorIndex = value.indexOf(" ");

  if (separatorIndex >= 0) {
    return {
      codeValue: value.slice(0, separatorIndex),
      phoneValue: value.slice(separatorIndex + 1),
    };
  }

  if (value.startsWith("+")) {
    try {
      const parsedNumber = phoneUtil.parse(value);
      const countryCode = parsedNumber.getCountryCode();
      const nationalNumber = String(parsedNumber.getNationalNumber());

      return {
        codeValue: countryCode ? `+${countryCode}` : fallbackCode,
        phoneValue: nationalNumber,
      };
    } catch {
      return {
        codeValue: fallbackCode,
        phoneValue: value,
      };
    }
  }

  return {
    codeValue: fallbackCode,
    phoneValue: value,
  };
}

function writePhoneValue(codeValue: string, phoneValue: string) {
  if (!codeValue && !phoneValue) {
    return null;
  }

  if (codeValue && phoneValue) {
    return `${codeValue} ${phoneValue}`;
  }

  if (codeValue) {
    return codeValue.startsWith("+") ? codeValue : `${codeValue} `;
  }

  return phoneValue;
}

function toStoredPhoneValue(
  codeValue: string,
  phoneValue: string,
): MarriagePhoneFieldValue | null {
  const normalizedCountryCode = sanitizeCountryCode(codeValue).replace(/^\+/, "");
  const normalizedPhoneNumber = phoneValue.trim().replace(/\s+/g, "");

  if (!normalizedCountryCode && !normalizedPhoneNumber) {
    return null;
  }

  return {
    countryCode: normalizedCountryCode,
    phoneNumber: normalizedPhoneNumber,
  };
}

function sanitizeCountryCode(value: string) {
  const sanitized = value.replace(/[^\d+]/g, "");

  if (sanitized.length === 0) {
    return "";
  }

  return sanitized.startsWith("+")
    ? `+${sanitized.slice(1).replace(/\+/g, "")}`
    : `+${sanitized.replace(/\+/g, "")}`;
}

function sanitizePhoneNumber(value: string) {
  return value.replace(/[^\d\s\-().]/g, "");
}

function getNormalizedPhoneValue(codeValue: string, phoneValue: string) {
  const nextCodeValue = sanitizeCountryCode(codeValue);
  const nextPhoneValue = phoneValue.trim();

  if (nextCodeValue.length === 0 && nextPhoneValue.length === 0) {
    return {
      isValid: !nextPhoneValue.length,
      normalizedValue: null,
    };
  }

  if (nextCodeValue.length === 0 || nextPhoneValue.length === 0) {
    return {
      isValid: false,
      normalizedValue: null,
    };
  }

  try {
    const parsedNumber = phoneUtil.parse(`${nextCodeValue} ${nextPhoneValue}`);

    if (!phoneUtil.isValidNumber(parsedNumber)) {
      return {
        isValid: false,
        normalizedValue: null,
      };
    }

    return {
      isValid: true,
      normalizedValue: phoneUtil.format(parsedNumber, PhoneNumberFormat.E164),
    };
  } catch {
    return {
      isValid: false,
      normalizedValue: null,
    };
  }
}

export function QuestionPhone({
  question,
  questionIndex,
  countryCode = "+98",
}: QuestionPhoneProps) {
  const { setValue, value } = useQuestionAnswer(question, questionIndex);
  const defaultCodeValue = countryCode.trim() || "+98";
  const initialValue = readPhoneValue(value, defaultCodeValue);
  const [codeValue, setCodeValue] = useState(initialValue.codeValue);
  const [phoneValue, setPhoneValue] = useState(initialValue.phoneValue);
  const lastCommittedValueRef = useRef(value);
  const normalizedPhoneState = getNormalizedPhoneValue(codeValue, phoneValue);
  const showInvalidState =
    codeValue.trim().length > 0 &&
    phoneValue.trim().length > 0 &&
    !normalizedPhoneState.isValid;
  const isAnswered =
    question.required === false
      ? normalizedPhoneState.isValid || phoneValue.trim().length === 0
      : normalizedPhoneState.isValid;

  useEffect(() => {
    if (value === lastCommittedValueRef.current) {
      return;
    }

    const nextValue = readPhoneValue(value, defaultCodeValue);

    setCodeValue(nextValue.codeValue);
    setPhoneValue(nextValue.phoneValue);
    lastCommittedValueRef.current = value;
  }, [defaultCodeValue, value]);

  const updateStoredValue = (nextCodeValue: string, nextPhoneValue: string) => {
    const draftValue = writePhoneValue(nextCodeValue, nextPhoneValue);
    const nextPhoneState = getNormalizedPhoneValue(
      nextCodeValue,
      nextPhoneValue,
    );
    const nextValue =
      draftValue === null
        ? null
        : nextPhoneState.isValid
          ? toStoredPhoneValue(nextCodeValue, nextPhoneValue)
          : null;

    lastCommittedValueRef.current = nextValue;
    setValue(nextValue);
  };

  return (
    <label
      data-question-answered={isAnswered ? "true" : "false"}
      data-question-type={question.type}
      className="block space-y-3"
    >
      <QuestionTitle question={question} />
      <div
        dir="ltr"
        className={[
          "flex h-[54px] w-full items-center rounded-[15px] border bg-white text-[#181818] focus-within:border-[#6F6F6F]",
          showInvalidState ? "border-[#F2465F]" : "border-[#E7D8D5]",
        ].join(" ")}
      >
        <div className="flex shrink-0 items-center pl-2.5 pr-2">
          <input
            type="tel"
            inputMode="tel"
            aria-label="Country code"
            maxLength={4}
            required={question.required}
            placeholder={defaultCodeValue}
            value={codeValue}
            onChange={(event) => {
              const nextCodeValue = sanitizeCountryCode(event.target.value);

              setCodeValue(nextCodeValue);
              updateStoredValue(nextCodeValue, phoneValue);
            }}
            className="w-[33px] border-0 bg-transparent p-0 text-left text-[14px] leading-none text-[#181818] tabular-nums outline-none placeholder:text-[#9D8F8C]"
          />
          <span aria-hidden="true" className="h-5 w-px bg-[#181818]/35" />
        </div>
        <span className="flex min-w-0 flex-1 items-center pr-4">
          <input
            type="tel"
            inputMode="tel"
            required={question.required}
            placeholder={question.extras.placeHolder?.replace(/^\+\d+\s*/, "")}
            value={phoneValue}
            onChange={(event) => {
              const nextPhoneValue = sanitizePhoneNumber(event.target.value);

              setPhoneValue(nextPhoneValue);
              updateStoredValue(codeValue, nextPhoneValue);
            }}
            dir="ltr"
            className="h-full w-full border-0 bg-transparent p-0 text-left text-[14px] leading-none text-[#181818] tabular-nums outline-none placeholder:text-[#9D8F8C]"
          />
        </span>
      </div>
      {showInvalidState ? (
        <span className="block text-[10px] font-semibold text-[#F2465F]">
          Enter a valid phone number with country code.
        </span>
      ) : null}
    </label>
  );
}

export default QuestionPhone;
