'use client';

import { useState, useCallback, useMemo } from 'react';
import { useRouter } from 'next/navigation';
import toast from 'react-hot-toast';
import ProductFormStepper from './ProductFormStepper';
import BasicInfoStep from './steps/BasicInfoStep';
import PricingStep from './steps/PricingStep';
import AttributesStep from './steps/AttributesStep';
import ImagesStep from './steps/ImagesStep';
import SeoStep from './steps/SeoStep';
import AdditionalInfoStep from './steps/AdditionalInfoStep';
import { getApiErrorMessage } from '@/lib/utils/apiError';
import type {
  Language,
  Category,
  Tag,
  Attribute,
  ProductData,
  FormErrors,
  ProductTranslation,
} from '@/types/product.types';

interface ProductFormProps {
  mode: 'create' | 'edit';
  initialData?: Partial<ProductData> & { id?: string };
  languages: Language[];
  categories: Category[];
  tags: Tag[];
  attributes: Attribute[];
  defaultLanguage: string;
}

const STEPS = [
  { id: 'basic',      label: 'Basic Info',       icon: '📝' },
  { id: 'pricing',    label: 'Pricing & Stock',   icon: '💰' },
  { id: 'attributes', label: 'Attributes',        icon: '🎯' },
  { id: 'images',     label: 'Images',            icon: '🖼️' },
  { id: 'seo',        label: 'SEO',               icon: '🔎' },
  { id: 'additional', label: 'Additional Info',   icon: '✨' },
] as const;

/**
 * Normalises the `errors` field returned from the API into a flat
 * { "dot.path": "message" } map usable by the form.
 *
 * The API now returns errors as Record<string, string> directly.
 * We keep the JSON-string fallback for backwards-compat.
 */
function normaliseApiErrors(errors: unknown): FormErrors {
  if (!errors) return {};

  // New format: plain object
  if (typeof errors === 'object' && !Array.isArray(errors)) {
    return errors as FormErrors;
  }

  // Old format: JSON string of Zod issues array
  if (typeof errors === 'string') {
    const result: FormErrors = {};
    try {
      const parsed: Array<{ path: Array<string | number>; message: string }> =
        JSON.parse(errors);
      for (const issue of parsed) {
        const key = issue.path.join('.');
        if (!result[key]) result[key] = issue.message;
      }
    } catch {
      result['_general'] = errors;
    }
    return result;
  }

  return {};
}

export default function ProductForm({
  mode,
  initialData,
  languages,
  categories,
  tags,
  attributes
}: ProductFormProps) {
  const router = useRouter();
  const isEditing = mode === 'edit';

  // Active languages sorted: default first
  const activeLanguages = useMemo<Language[]>(() => {
    return languages
      .filter((l) => l.is_active)
      .sort((a, b) => {
        if (a.is_default) return -1;
        if (b.is_default) return 1;
        return a.name.localeCompare(b.name);
      });
  }, [languages]);

  const defaultLang =
    activeLanguages.find((l) => l.is_default) ?? activeLanguages[0];

  // Build blank translation object for a given language code
  const blankTranslation = useCallback(
    (code: string): ProductTranslation => ({
      language_code: code,
      name: '',
      slug: '',
      short_description: '',
      description: '',
      meta_title: '',
      meta_description: '',
      meta_keywords: '',
      product_schemas: {},
    }),
    [],
  );

  const initialTranslations = useMemo<ProductTranslation[]>(() => {
    if (isEditing && Array.isArray(initialData?.translations)) {
      // Ensure every active language has an entry
      return activeLanguages.map((lang) => {
        const existing = (initialData!.translations as ProductTranslation[]).find(
          (t) => t.language_code === lang.code,
        );
        return existing ?? blankTranslation(lang.code);
      });
    }
    return activeLanguages.map((l) => blankTranslation(l.code));
  }, [isEditing, initialData, activeLanguages, blankTranslation]);

  // ─── Form state ──────────────────────────────────────────────────────────

  const [formData, setFormData] = useState<ProductData>({
    sku:                 initialData?.sku                 ?? '',
    type:                initialData?.type                ?? 'simple',
    category_id:         initialData?.category_id         ?? null,
    price:               initialData?.price               ?? 0,
    compare_price:       initialData?.compare_price       ?? null,
    cost_price:          initialData?.cost_price          ?? null,
    stock_quantity:      initialData?.stock_quantity      ?? 0,
    stock_status:        initialData?.stock_status        ?? 'out_of_stock',
    min_stock_threshold: initialData?.min_stock_threshold ?? 0,
    allow_backorder:     initialData?.allow_backorder     ?? false,
    is_active:           initialData?.is_active           ?? true,
    is_featured:         initialData?.is_featured         ?? false,
    is_indexable:        initialData?.is_indexable        ?? true,
    visibility:          initialData?.visibility          ?? 'visible',
    translations:        initialTranslations,
    images:              initialData?.images              ?? [],
    attribute_ids:       initialData?.attribute_ids       ?? [],
    variations:          initialData?.variations          ?? [],
    tag_ids:             initialData?.tag_ids             ?? [],
    faqs:                initialData?.faqs                ?? [],
    related_product_ids: initialData?.related_product_ids ?? [],
  });

  const [currentStep, setCurrentStep] = useState(0);
  const [loading, setLoading]         = useState(false);
  const [errors, setErrors]           = useState<FormErrors>({});

  // ─── Updaters ────────────────────────────────────────────────────────────

  const updateFormData = useCallback(
    <K extends keyof ProductData>(key: K, value: ProductData[K]) => {
      setFormData((prev) => ({ ...prev, [key]: value }));
      // Clear the error for this field when user edits it
      setErrors((prev) => {
        if (!prev[key]) return prev;
        const next = { ...prev };
        delete next[key as string];
        return next;
      });
    },
    [],
  );

  const updateTranslation = useCallback(
    (languageCode: string, field: keyof ProductTranslation, value: unknown) => {
      setFormData((prev) => {
        const idx = prev.translations.findIndex(
          (t) => t.language_code === languageCode,
        );
        const next = [...prev.translations];
        if (idx >= 0) {
          next[idx] = { ...next[idx], [field]: value };
        } else {
          next.push({ ...blankTranslation(languageCode), [field]: value });
        }
        return { ...prev, translations: next };
      });
      // Clear translation-level error
      setErrors((prev) => {
        const errKey = `translations.${languageCode}.${field}`;
        if (!prev[errKey]) return prev;
        const next = { ...prev };
        delete next[errKey];
        return next;
      });
    },
    [blankTranslation],
  );

  // ─── Navigation ──────────────────────────────────────────────────────────

  const handleNext = useCallback(
    () => setCurrentStep((p) => Math.min(p + 1, STEPS.length - 1)),
    [],
  );
  const handlePrevious = useCallback(
    () => setCurrentStep((p) => Math.max(p - 1, 0)),
    [],
  );

  // ─── Client-side pre-flight validation ───────────────────────────────────

  function clientValidate(): FormErrors {
    const errs: FormErrors = {};

    if (!formData.sku.trim()) errs['sku'] = 'SKU is required';
    if (formData.price < 0)   errs['price'] = 'Price cannot be negative';

    const hasName = formData.translations.some((t) => t.name.trim().length > 0);
    if (!hasName) errs['translations'] = 'At least one translation with a name is required';

    formData.translations.forEach((t, i) => {
      if (t.name.trim() && !t.slug.trim()) {
        errs[`translations.${i}.slug`] = `Slug is required for ${t.language_code}`;
      }
    });

    return errs;
  }

  // ─── Submit ───────────────────────────────────────────────────────────────

  async function handleSubmit() {
    // Client-side check first
    const clientErrs = clientValidate();
    if (Object.keys(clientErrs).length > 0) {
      setErrors(clientErrs);
      // Jump to first step that has an error
      const firstErrKey = Object.keys(clientErrs)[0];
      if (firstErrKey === 'sku' || firstErrKey === 'translations') {
        setCurrentStep(0);
      } else if (firstErrKey === 'price') {
        setCurrentStep(1);
      }
      // Show the actual messages (e.g. "SKU is required; Price must be
      // positive"), not just "fix the highlighted fields" — same
      // summarizer used for the server-side validation branch below.
      toast.error(getApiErrorMessage({ errors: clientErrs }, 'Please fix the highlighted errors before saving'), { duration: 6000 });
      return;
    }

    setLoading(true);
    setErrors({});

    try {
      const url    = isEditing ? `/api/products/${initialData?.id}` : '/api/products';
      const method = isEditing ? 'PUT' : 'POST';

      const payload: ProductData = {
        ...formData,
        translations: formData.translations.filter((t) => t.name.trim().length > 0),
      };

      const res  = await fetch(url, {
        method,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });
      const data = await res.json() as {
        success: boolean;
        message?: string;
        error?: string; // set by serverErrorResponse() — the real underlying reason
        errors?: Record<string, string> | string;
      };

      if (!res.ok || !data.success) {
        // Try to surface field-level errors from Zod
        if (data.errors) {
          const fieldErrors = normaliseApiErrors(data.errors);
          setErrors(fieldErrors);

          // Navigate to the step most likely to contain the first error
          const firstKey = Object.keys(fieldErrors)[0] ?? '';
          if (firstKey.startsWith('translations') || firstKey === 'sku') {
            setCurrentStep(0);
          } else if (['price', 'compare_price', 'cost_price', 'stock_quantity', 'stock_status'].some((k) => firstKey.startsWith(k))) {
            setCurrentStep(1);
          } else if (firstKey.startsWith('attribute') || firstKey.startsWith('variation')) {
            setCurrentStep(2);
          } else if (firstKey.startsWith('image')) {
            setCurrentStep(3);
          } else if (['meta'].some((k) => firstKey.startsWith(k))) {
            setCurrentStep(4);
          }
          // Show the actual validation messages, not just "fix the
          // highlighted fields" — getApiErrorMessage() summarizes the real
          // per-field messages (handles both the plain-object and the
          // JSON-string-of-Zod-issues shapes the backend can send).
          toast.error(getApiErrorMessage(data, 'Please fix the highlighted errors before saving'), { duration: 6000 });
        } else {
          // Not a validation failure — a real backend/DB error. Show the
          // actual reason (data.error, set by serverErrorResponse()) rather
          // than just the generic "Failed to save product" — that's what
          // makes a bug like a bad INSERT column list fixable from the
          // toast alone instead of needing someone to go find server logs.
          toast.error(getApiErrorMessage(data, 'Failed to save product'), { duration: 6000 });
        }
        return;
      }

      toast.success(
        data.message ?? (isEditing ? 'Product updated successfully' : 'Product created successfully'),
      );
      router.push('/admin/dashboard/products');
      router.refresh();
    } catch {
      toast.error('Network error — please try again');
    } finally {
      setLoading(false);
    }
  }

  // ─── Guard ────────────────────────────────────────────────────────────────

  if (activeLanguages.length === 0) {
    return (
      <div
        className="p-6 rounded-lg text-center"
        style={{
          background: 'var(--color-surface)',
          border: '1px solid var(--color-border)',
        }}
      >
        <p style={{ color: 'var(--color-text-secondary)' }}>
          No active languages found. Please add languages first.
        </p>
      </div>
    );
  }

  // ─── Render ───────────────────────────────────────────────────────────────

  const sharedStepProps = {
    formData,
    updateFormData,
    errors,
  };

  return (
    <div className="space-y-6">
      <ProductFormStepper
        steps={STEPS}
        currentStep={currentStep}
        onStepClick={setCurrentStep}
      />

      {/* General error banner */}
      {errors['_general'] && (
        <div
          className="px-4 py-3 rounded-lg text-sm"
          style={{
            background: 'var(--color-danger-light)',
            border: '1px solid var(--color-danger)',
            color: 'var(--color-danger)',
          }}
        >
          {errors['_general']}
        </div>
      )}

      {/* Translation-level error banner */}
      {errors['translations'] && (
        <div
          className="px-4 py-3 rounded-lg text-sm"
          style={{
            background: 'var(--color-danger-light)',
            border: '1px solid var(--color-danger)',
            color: 'var(--color-danger)',
          }}
        >
          {errors['translations']}
        </div>
      )}

      <div
        className="p-6 md:p-8"
        style={{
          background: 'var(--color-surface)',
          border: '1px solid var(--color-border)',
          borderRadius: 'var(--radius-card)',
          boxShadow: 'var(--shadow-card-md)',
        }}
      >
        {currentStep === 0 && (
          <BasicInfoStep
            {...sharedStepProps}
            updateTranslation={updateTranslation}
            languages={activeLanguages}
            defaultLanguage={defaultLang}
            categories={categories}
          />
        )}

        {currentStep === 1 && (
          <PricingStep {...sharedStepProps} />
        )}

        {currentStep === 2 && (
          <AttributesStep
            {...sharedStepProps}
            attributes={attributes}
            languages={activeLanguages}
            defaultLanguage={defaultLang}
          />
        )}

        {currentStep === 3 && (
          <ImagesStep
            {...sharedStepProps}
            languages={activeLanguages}
            defaultLanguage={defaultLang}
          />
        )}

        {currentStep === 4 && (
          <SeoStep
            {...sharedStepProps}
            updateTranslation={updateTranslation}
            languages={activeLanguages}
            defaultLanguage={defaultLang}
          />
        )}

        {currentStep === 5 && (
          <AdditionalInfoStep
            {...sharedStepProps}
            tags={tags}
            languages={activeLanguages}
            defaultLanguage={defaultLang}
          />
        )}

        {/* Navigation */}
        <div
          className="flex justify-between pt-6 mt-6 border-t"
          style={{ borderColor: 'var(--color-border)' }}
        >
          <button
            type="button"
            onClick={handlePrevious}
            disabled={currentStep === 0}
            className="px-6 py-2.5 rounded-lg text-sm font-medium transition-all disabled:opacity-50 hover:opacity-80"
            style={{
              background: 'var(--color-surface-alt)',
              color: 'var(--color-text)',
              border: '1px solid var(--color-border)',
            }}
          >
            Previous
          </button>

          <div className="flex gap-3">
            <button
              type="button"
              onClick={() => router.back()}
              className="px-6 py-2.5 rounded-lg text-sm font-medium transition-all hover:opacity-80"
              style={{
                background: 'var(--color-surface-alt)',
                color: 'var(--color-text)',
                border: '1px solid var(--color-border)',
              }}
            >
              Cancel
            </button>

            {currentStep === STEPS.length - 1 ? (
              <button
                type="button"
                onClick={handleSubmit}
                disabled={loading}
                className="px-6 py-2.5 rounded-lg text-sm font-medium transition-all disabled:opacity-50 hover:opacity-90"
                style={{ background: 'var(--color-cta)', color: 'white' }}
              >
                {loading ? (
                  <span className="flex items-center gap-2">
                    <svg className="animate-spin h-4 w-4" viewBox="0 0 24 24">
                      <circle
                        className="opacity-25"
                        cx="12" cy="12" r="10"
                        stroke="currentColor" strokeWidth="4" fill="none"
                      />
                      <path
                        className="opacity-75"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                      />
                    </svg>
                    Saving…
                  </span>
                ) : isEditing ? 'Update Product' : 'Create Product'}
              </button>
            ) : (
              <button
                type="button"
                onClick={handleNext}
                className="px-6 py-2.5 rounded-lg text-sm font-medium transition-all hover:opacity-90"
                style={{ background: 'var(--color-cta)', color: 'white' }}
              >
                Next →
              </button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}