﻿// react
import React, { useCallback, useEffect, useRef, useState } from "react";
// third-party
import { useForm, useWatch } from "react-hook-form";
import { toast } from "react-toastify";
// application
import { IBrand, IModel } from "~/admin/interfaces/vehicle";
import { vehiclesApi } from "~/admin/services/vehiclesApi";
import { InputImageSingle } from "./InputImageSingle";

interface Props {
  model?: IModel | null;
  /** Listado completo de modelos (para orden único por marca y sugerencia al crear) */
  existingModels: IModel[];
  onSave: (formData: FormData) => void;
  onCancel: () => void;
}

export const ModelForm = ({ model, existingModels, onSave, onCancel }: Props) => {
  const [brands, setBrands] = useState<IBrand[]>([]);
  const [loading, setLoading] = useState(true);
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [positionTakenMessage, setPositionTakenMessage] = useState<string | null>(null);
  const prevBrandIdRef = useRef<number | null>(null);

  const {
    register,
    handleSubmit,
    setValue,
    reset,
    control,
    formState: { errors },
  } = useForm<IModel>({
    defaultValues: model
      ? {
          name: model.name,
          vehicle_brandID: model.vehicle_brandID,
          imageUrl: model.imageUrl,
          status: model.status === 1 || model.status === true,
          position: model.sort_position ?? model.position ?? 0,
        }
      : { name: "", vehicle_brandID: 0, imageUrl: "", status: true, position: 1 },
  });

  const watchedBrandId = useWatch({ control, name: "vehicle_brandID" });

  const validatePositionAvailable = useCallback(
    (raw: string, brandId: number): boolean => {
      const trimmed = String(raw).trim();
      if (trimmed === "") {
        setPositionTakenMessage(null);
        return true;
      }
      const n = parseInt(trimmed, 10);
      if (Number.isNaN(n) || n < 0) {
        setPositionTakenMessage(null);
        return true;
      }
      if (!brandId || brandId === 0) {
        setPositionTakenMessage(null);
        return true;
      }
      const taken = existingModels.some(
        (m) =>
          m.vehicle_brandID === brandId &&
          m.id !== model?.id &&
          Number(m.sort_position ?? m.position ?? 0) === n,
      );
      if (taken) {
        setPositionTakenMessage("Este orden ya lo usa otro modelo de la misma marca.");
        return false;
      }
      setPositionTakenMessage(null);
      return true;
    },
    [existingModels, model?.id],
  );

  const blockNonDigitPositionKeys = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.ctrlKey || e.metaKey || e.altKey) return;
    const allowed = [
      "Backspace",
      "Delete",
      "Tab",
      "Escape",
      "Enter",
      "ArrowLeft",
      "ArrowRight",
      "ArrowUp",
      "ArrowDown",
      "Home",
      "End",
    ];
    if (allowed.includes(e.key)) return;
    if (e.key.length === 1 && /[0-9]/.test(e.key)) return;
    e.preventDefault();
  };

  const positionRegister = register("position", {
    setValueAs: (v) => {
      const digits = String(v ?? "").replace(/\D/g, "");
      if (digits === "") return 0;
      const n = parseInt(digits, 10);
      return Number.isNaN(n) ? 0 : n;
    },
    min: { value: 0, message: "No puede ser negativo" },
  });

  const sanitizePositionPaste = (e: React.ClipboardEvent<HTMLInputElement>) => {
    e.preventDefault();
    const paste = (e.clipboardData.getData("text") || "").replace(/\D/g, "");
    const input = e.currentTarget;
    const start = input.selectionStart ?? 0;
    const end = input.selectionEnd ?? 0;
    const merged = `${input.value.slice(0, start)}${paste}${input.value.slice(end)}`;
    const next = merged.replace(/\D/g, "");
    input.value = next;
    const caret = Math.min(start + paste.length, next.length);
    requestAnimationFrame(() => input.setSelectionRange(caret, caret));
    positionRegister.onChange({
      target: input,
      type: "change",
    } as React.ChangeEvent<HTMLInputElement>);
  };

  useEffect(() => {
    loadBrands();
  }, []);

  useEffect(() => {
    if (!model) {
      prevBrandIdRef.current = null;
    }
  }, [model]);

  useEffect(() => {
    if (model) {
      reset({
        ...model,
        status: model.status === 1 || model.status === true,
        position: model.sort_position ?? model.position ?? 0,
      });
      prevBrandIdRef.current = model.vehicle_brandID;
      validatePositionAvailable(
        String(model.sort_position ?? model.position ?? 0),
        model.vehicle_brandID,
      );
      // Asegurar que la marca se seleccione después del reset
      setTimeout(() => {
        setValue("vehicle_brandID", model.vehicle_brandID);
      }, 100);
    }
  }, [model, reset, validatePositionAvailable]);

  useEffect(() => {
    if (model) return;
    const bid = Number(watchedBrandId) || 0;
    if (!bid) return;
    if (prevBrandIdRef.current === bid) return;
    prevBrandIdRef.current = bid;
    const max = existingModels
      .filter((m) => m.vehicle_brandID === bid)
      .reduce((acc, m) => Math.max(acc, Number(m.sort_position ?? m.position ?? 0)), 0);
    const nextPos = max + 1;
    setValue("position", nextPos);
    validatePositionAvailable(String(nextPos), bid);
  }, [watchedBrandId, model, existingModels, setValue, validatePositionAvailable]);

  const loadBrands = async () => {
    try {
      setLoading(true);
      const data = await vehiclesApi.getAllBrands();
      setBrands(data);

      if (model?.vehicle_brandID) {
        setValue("vehicle_brandID", model.vehicle_brandID);
      }
    } catch (error: any) {
      toast.error("Error al cargar marcas");
    } finally {
      setLoading(false);
    }
  };

  const onSubmit = (data: IModel) => {
    const bid = Number(data.vehicle_brandID) || 0;
    const posStr =
      typeof data.position === "number" && !Number.isNaN(data.position)
        ? String(data.position)
        : String(data.position ?? "");
    if (!validatePositionAvailable(posStr, bid)) {
      return;
    }

    const formData = new FormData();
    formData.append("name", data.name);
    formData.append("vehicle_brandID", String(data.vehicle_brandID));
    formData.append("status", (model ? data.status : true) ? "1" : "0");
    const pos =
      typeof data.position === "number" && !Number.isNaN(data.position)
        ? data.position
        : parseInt(String(data.position ?? "0"), 10) || 0;
    formData.append("position", String(pos));

    if (model?.id) {
      formData.append("id", String(model.id));
    }
    if (selectedFile) {
      formData.append("image", selectedFile);
    } else if (model?.imageUrl) {
      formData.append("existingImageUrl", model.imageUrl);
    }

    onSave(formData);
  };

  return (
    <div className="card">
      <div className="card-header">
        <h3>{model ? `Editar: ${model.name}` : "Nuevo Modelo"}</h3>
      </div>
      <div className="card-body">
        <form onSubmit={handleSubmit(onSubmit)}>
          <div className="row">
            <div className="col-md-6">
              <div className="form-group">
                <label>Nombre del Modelo *</label>
                <input
                  type="text"
                  placeholder="Ej: Corolla"
                  className={`form-control ${errors.name ? "is-invalid" : ""}`}
                  {...register("name", { required: "El nombre es requerido" })}
                />
                {errors.name && (
                  <div className="invalid-feedback">{errors.name.message}</div>
                )}
              </div>
            </div>

            <div className="col-md-6">
              <div className="form-group">
                <label>Marca asignada *</label>
                <select
                  className={`form-control ${
                    errors.vehicle_brandID ? "is-invalid" : ""
                  }`}
                  {...register("vehicle_brandID", {
                    required: "Seleccione una marca",
                    validate: (val) => val != 0 || "Debe seleccionar una marca",
                  })}
                >
                  <option value="0">-- Seleccione --</option>
                  {brands.map((brand) => (
                    <option key={brand.id} value={brand.id}>
                      {brand.name}
                    </option>
                  ))}
                </select>
                {errors.vehicle_brandID && (
                  <div className="invalid-feedback">
                    {errors.vehicle_brandID.message}
                  </div>
                )}
              </div>
            </div>

            <div className="col-md-6">
              <div className="form-group">
                <label>Orden (posición) *</label>
                <input
                  type="text"
                  inputMode="numeric"
                  pattern="[0-9]*"
                  autoComplete="off"
                  placeholder="0"
                  className={`form-control ${
                    errors.position || positionTakenMessage ? "is-invalid" : ""
                  }`}
                  name={positionRegister.name}
                  ref={positionRegister.ref}
                  onChange={(e) => {
                    const el = e.currentTarget;
                    const next = el.value.replace(/\D/g, "");
                    if (el.value !== next) el.value = next;
                    positionRegister.onChange(e);
                  }}
                  onKeyDown={blockNonDigitPositionKeys}
                  onPaste={sanitizePositionPaste}
                  onBlur={(e) => {
                    positionRegister.onBlur(e);
                    const bid = Number(watchedBrandId) || 0;
                    validatePositionAvailable(e.currentTarget.value, bid);
                  }}
                  onKeyUp={(e) => {
                    const bid = Number(watchedBrandId) || 0;
                    validatePositionAvailable((e.target as HTMLInputElement).value, bid);
                  }}
                />
               
                {positionTakenMessage && (
                  <div className="invalid-feedback d-block">{positionTakenMessage}</div>
                )}
                {errors.position && !positionTakenMessage && (
                  <div className="invalid-feedback d-block">{errors.position.message}</div>
                )}
              </div>
            </div>

            <div className="col-md-12 mt-3">
              <InputImageSingle
                initialImage={model?.imageUrl}
                onFileChange={setSelectedFile}
                inputId="model-image"
                helperText="Medidas recomendadas: 800 × 800 px (imagen cuadrada, proporción 1:1)."
              />
            </div>

            <div className="col-md-12 mt-3">
              <div className="form-check">
                <input
                  type="checkbox"
                  id="model-status"
                  className="form-check-input"
                  {...register("status")}
                />
                <label className="form-check-label" htmlFor="model-status">
                  Activo
                </label>
              </div>
              <small className="text-muted">Desactiva el modelo para ocultarlo sin eliminarlo.</small>
            </div>
          </div>

          <div className="form-actions mt-4">
            <button
              type="submit"
              className="btn btn-primary"
              disabled={loading}
            >
              <i className="fas fa-save" /> Guardar
            </button>
            <button
              type="button"
              className="btn btn-secondary ml-2"
              onClick={onCancel}
            >
              Cancelar
            </button>
          </div>
        </form>
      </div>
    </div>
  );
};
