"use client";

/**
 * V2FormContext
 * 
 * V2 컴포넌트들이 폼 상태를 공유하고
 * 조건부 로직, 저장/검증/초기화 등의 폼 액션을 처리할 수 있도록 하는 Context
 * 
 * 레거시 컴포넌트와의 호환성을 유지하면서 새로운 기능을 제공합니다.
 */

import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from "react";
import { ConditionalConfig, CascadingConfig } from "@/types/v2-components";
import { ValidationRule } from "@/types/v2-core";
import type {
  FormStatus,
  FieldError,
  FieldState,
  SubmitConfig,
  SubmitResult,
  ValidationResult,
  FormEventDetail,
} from "@/types/v2-form";

// ===== 레거시 타입 호환 (기존 코드와 호환) =====

export interface FormFieldState {
  value: unknown;
  disabled?: boolean;
  visible?: boolean;
  error?: string;
}

export interface FormState {
  [fieldId: string]: FormFieldState;
}

// ===== 확장된 Context 타입 =====

export interface V2FormContextValue {
  // === 기존 기능 (하위 호환) ===
  formData: Record<string, unknown>;
  fieldStates: FormState;
  
  getValue: (fieldId: string) => unknown;
  setValue: (fieldId: string, value: unknown) => void;
  setValues: (values: Record<string, unknown>) => void;
  
  evaluateCondition: (fieldId: string, config?: ConditionalConfig) => {
    visible: boolean;
    disabled: boolean;
  };
  
  getCascadingFilter: (config?: CascadingConfig) => unknown;
  
  registerField: (fieldId: string, initialValue?: unknown) => void;
  unregisterField: (fieldId: string) => void;
  
  // === 새로운 기능 ===
  
  // 원본 데이터 (수정 모드)
  originalData: Record<string, unknown>;
  
  // 폼 상태
  status: FormStatus;
  errors: FieldError[];
  
  // 폼 액션
  submit: (config?: Partial<SubmitConfig>) => Promise<SubmitResult>;
  reset: () => void;
  validate: (fieldIds?: string[]) => Promise<ValidationResult>;
  clear: () => void;
  
  // 초기 데이터 설정 (수정 모드 진입)
  setInitialData: (data: Record<string, unknown>) => void;
  
  // 에러 관리
  setFieldError: (fieldId: string, error: string, type?: FieldError["type"]) => void;
  clearFieldError: (fieldId: string) => void;
  clearAllErrors: () => void;
  
  // dirty 체크
  getChangedFields: () => string[];
  hasChanges: () => boolean;
  
  // 리피터 데이터 관리
  getRepeaterData: (fieldName: string) => unknown[];
  setRepeaterData: (fieldName: string, data: unknown[]) => void;
  addRepeaterRow: (fieldName: string, row: Record<string, unknown>) => void;
  updateRepeaterRow: (fieldName: string, index: number, row: Record<string, unknown>) => void;
  deleteRepeaterRow: (fieldName: string, index: number) => void;
}

// ===== Context 생성 =====

const V2FormContext = createContext<V2FormContextValue | null>(null);

// ===== 조건 평가 함수 =====

function evaluateOperator(
  fieldValue: unknown,
  operator: ConditionalConfig["operator"],
  conditionValue: unknown
): boolean {
  switch (operator) {
    case "=":
      return fieldValue === conditionValue;
    case "!=":
      return fieldValue !== conditionValue;
    case ">":
      return Number(fieldValue) > Number(conditionValue);
    case "<":
      return Number(fieldValue) < Number(conditionValue);
    case "in":
      if (Array.isArray(conditionValue)) {
        return conditionValue.includes(fieldValue);
      }
      return false;
    case "notIn":
      if (Array.isArray(conditionValue)) {
        return !conditionValue.includes(fieldValue);
      }
      return true;
    case "isEmpty":
      return fieldValue === null || fieldValue === undefined || fieldValue === "" || 
        (Array.isArray(fieldValue) && fieldValue.length === 0);
    case "isNotEmpty":
      return fieldValue !== null && fieldValue !== undefined && fieldValue !== "" &&
        !(Array.isArray(fieldValue) && fieldValue.length === 0);
    default:
      return true;
  }
}

// ===== 초기 상태 =====

const initialFormStatus: FormStatus = {
  isSubmitting: false,
  isValidating: false,
  isDirty: false,
  isValid: true,
  isLoading: false,
  submitCount: 0,
};

// ===== Provider Props =====

interface V2FormProviderProps {
  children: React.ReactNode;
  initialValues?: Record<string, unknown>;
  onChange?: (formData: Record<string, unknown>) => void;
  
  // 새로운 Props
  submitConfig?: SubmitConfig;
  onSubmit?: (data: Record<string, unknown>, config: SubmitConfig) => Promise<SubmitResult>;
  onError?: (errors: FieldError[]) => void;
  onReset?: () => void;
  
  // 레거시 호환성
  emitLegacyEvents?: boolean; // beforeFormSave 등 레거시 이벤트 발생 여부 (기본: true)
}

// ===== Provider 컴포넌트 =====

export function V2FormProvider({
  children,
  initialValues = {},
  onChange,
  submitConfig: defaultSubmitConfig,
  onSubmit,
  onError,
  onReset,
  emitLegacyEvents = true,
}: V2FormProviderProps) {
  // 기존 상태
  const [formData, setFormData] = useState<Record<string, unknown>>(initialValues);
  const [fieldStates, setFieldStates] = useState<FormState>({});

  // 새로운 상태
  const [originalData, setOriginalData] = useState<Record<string, unknown>>(initialValues);
  const [status, setStatus] = useState<FormStatus>(initialFormStatus);
  const [errors, setErrors] = useState<FieldError[]>([]);
  
  // 필드별 검증 규칙 저장
  const validationRulesRef = useRef<Map<string, ValidationRule[]>>(new Map());

  // ===== 기존 기능 =====

  const getValue = useCallback((fieldId: string): unknown => {
    return formData[fieldId];
  }, [formData]);

  const setValue = useCallback((fieldId: string, value: unknown) => {
    setFormData(prev => {
      const newData = { ...prev, [fieldId]: value };
      
      // dirty 상태 업데이트
      setStatus(s => ({ ...s, isDirty: true }));
      
      onChange?.(newData);
      return newData;
    });
  }, [onChange]);

  const setValues = useCallback((values: Record<string, unknown>) => {
    setFormData(prev => {
      const newData = { ...prev, ...values };
      setStatus(s => ({ ...s, isDirty: true }));
      onChange?.(newData);
      return newData;
    });
  }, [onChange]);

  const evaluateCondition = useCallback((
    fieldId: string,
    config?: ConditionalConfig
  ): { visible: boolean; disabled: boolean } => {
    if (!config || !config.enabled) {
      return { visible: true, disabled: false };
    }

    const { field, operator, value, action } = config;
    const fieldValue = formData[field];
    const conditionMet = evaluateOperator(fieldValue, operator, value);

    switch (action) {
      case "show":
        return { visible: conditionMet, disabled: false };
      case "hide":
        return { visible: !conditionMet, disabled: false };
      case "enable":
        return { visible: true, disabled: !conditionMet };
      case "disable":
        return { visible: true, disabled: conditionMet };
      default:
        return { visible: true, disabled: false };
    }
  }, [formData]);

  const getCascadingFilter = useCallback((config?: CascadingConfig): unknown => {
    if (!config) return undefined;
    return formData[config.parentField];
  }, [formData]);

  const registerField = useCallback((fieldId: string, initialValue?: unknown) => {
    if (initialValue !== undefined && formData[fieldId] === undefined) {
      setFormData(prev => ({ ...prev, [fieldId]: initialValue }));
    }
    setFieldStates(prev => ({
      ...prev,
      [fieldId]: { value: initialValue, visible: true, disabled: false },
    }));
  }, [formData]);

  const unregisterField = useCallback((fieldId: string) => {
    setFieldStates(prev => {
      const next = { ...prev };
      delete next[fieldId];
      return next;
    });
    validationRulesRef.current.delete(fieldId);
  }, []);

  // ===== 새로운 기능: 폼 액션 =====

  // 검증
  const validate = useCallback(async (fieldIds?: string[]): Promise<ValidationResult> => {
    setStatus(s => ({ ...s, isValidating: true }));
    
    const newErrors: FieldError[] = [];
    const fieldsToValidate = fieldIds || Array.from(validationRulesRef.current.keys());
    
    for (const fieldId of fieldsToValidate) {
      const rules = validationRulesRef.current.get(fieldId);
      if (!rules) continue;
      
      const value = formData[fieldId];
      
      for (const rule of rules) {
        let isValid = true;
        
        switch (rule.type) {
          case "required":
            isValid = value !== null && value !== undefined && value !== "";
            break;
          case "minLength":
            isValid = typeof value === "string" && value.length >= (rule.value as number);
            break;
          case "maxLength":
            isValid = typeof value === "string" && value.length <= (rule.value as number);
            break;
          case "min":
            isValid = typeof value === "number" && value >= (rule.value as number);
            break;
          case "max":
            isValid = typeof value === "number" && value <= (rule.value as number);
            break;
          case "pattern":
            isValid = typeof value === "string" && new RegExp(rule.value as string).test(value);
            break;
          case "email":
            isValid = typeof value === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
            break;
          case "url":
            isValid = typeof value === "string" && /^https?:\/\/.+/.test(value);
            break;
        }
        
        if (!isValid) {
          newErrors.push({
            fieldId,
            message: rule.message,
            type: rule.type === "required" ? "required" : "format",
          });
          break; // 첫 번째 에러만 기록
        }
      }
    }
    
    setErrors(newErrors);
    setStatus(s => ({ 
      ...s, 
      isValidating: false, 
      isValid: newErrors.length === 0 
    }));
    
    return { valid: newErrors.length === 0, errors: newErrors };
  }, [formData]);

  // 저장
  const submit = useCallback(async (config?: Partial<SubmitConfig>): Promise<SubmitResult> => {
    const finalConfig = { ...defaultSubmitConfig, ...config } as SubmitConfig;
    
    setStatus(s => ({ ...s, isSubmitting: true, submitCount: s.submitCount + 1 }));
    
    try {
      // 1. 검증
      if (finalConfig.validateBeforeSubmit !== false) {
        const validation = await validate();
        if (!validation.valid) {
          onError?.(validation.errors);
          return { success: false, error: "검증 실패", errors: validation.errors };
        }
      }
      
      // 2. 레거시 이벤트 발생 (리피터 데이터 수집)
      let collectedData = { ...formData };
      
      if (emitLegacyEvents && typeof window !== "undefined") {
        const eventDetail: FormEventDetail = { formData: {} };
        const legacyEvent = new CustomEvent("beforeFormSave", { detail: eventDetail });
        window.dispatchEvent(legacyEvent);
        
        // 이벤트에서 수집된 데이터 병합 (리피터 등)
        collectedData = { ...collectedData, ...eventDetail.formData };
      }
      
      // 3. beforeSubmit 콜백
      if (finalConfig.onBeforeSubmit) {
        collectedData = await finalConfig.onBeforeSubmit(collectedData);
      }
      
      // 4. 추가 데이터 병합
      if (finalConfig.additionalData) {
        collectedData = { ...collectedData, ...finalConfig.additionalData };
      }
      
      // 5. 저장 실행
      let result: SubmitResult;
      
      if (onSubmit) {
        result = await onSubmit(collectedData, finalConfig);
      } else {
        // 기본 저장 로직 (API 호출)
        // 실제 구현은 외부에서 onSubmit으로 제공
        result = { success: true, data: collectedData };
      }
      
      // 6. 성공 시 처리
      if (result.success) {
        setOriginalData({ ...formData });
        setStatus(s => ({ ...s, isDirty: false }));
        
        // afterFormSave 이벤트 발생
        if (emitLegacyEvents && typeof window !== "undefined") {
          window.dispatchEvent(new CustomEvent("afterFormSave", {
            detail: { success: true, data: result.data }
          }));
        }
        
        // afterSubmit 콜백
        finalConfig.onAfterSubmit?.(result);
      }
      
      return result;
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : "저장 중 오류 발생";
      return { success: false, error: errorMessage };
    } finally {
      setStatus(s => ({ ...s, isSubmitting: false }));
    }
  }, [formData, defaultSubmitConfig, validate, onSubmit, onError, emitLegacyEvents]);

  // 초기화 (원본 데이터로 복원)
  const reset = useCallback(() => {
    setFormData({ ...originalData });
    setErrors([]);
    setStatus(s => ({ ...s, isDirty: false, isValid: true }));
    onReset?.();
  }, [originalData, onReset]);

  // 비우기
  const clear = useCallback(() => {
    setFormData({});
    setErrors([]);
    setStatus(s => ({ ...s, isDirty: true, isValid: true }));
  }, []);

  // 초기 데이터 설정 (수정 모드 진입)
  const setInitialData = useCallback((data: Record<string, unknown>) => {
    setFormData(data);
    setOriginalData(data);
    setStatus(s => ({ ...s, isDirty: false }));
  }, []);

  // ===== 에러 관리 =====

  const setFieldError = useCallback((fieldId: string, message: string, type: FieldError["type"] = "custom") => {
    setErrors(prev => {
      const filtered = prev.filter(e => e.fieldId !== fieldId);
      return [...filtered, { fieldId, message, type }];
    });
    setStatus(s => ({ ...s, isValid: false }));
  }, []);

  const clearFieldError = useCallback((fieldId: string) => {
    setErrors(prev => {
      const filtered = prev.filter(e => e.fieldId !== fieldId);
      return filtered;
    });
  }, []);

  const clearAllErrors = useCallback(() => {
    setErrors([]);
    setStatus(s => ({ ...s, isValid: true }));
  }, []);

  // ===== dirty 체크 =====

  const getChangedFields = useCallback((): string[] => {
    const changed: string[] = [];
    const allKeys = new Set([...Object.keys(formData), ...Object.keys(originalData)]);
    
    for (const key of allKeys) {
      if (JSON.stringify(formData[key]) !== JSON.stringify(originalData[key])) {
        changed.push(key);
      }
    }
    
    return changed;
  }, [formData, originalData]);

  const hasChanges = useCallback((): boolean => {
    return JSON.stringify(formData) !== JSON.stringify(originalData);
  }, [formData, originalData]);

  // ===== 리피터 데이터 관리 =====

  const getRepeaterData = useCallback((fieldName: string): unknown[] => {
    const data = formData[fieldName];
    if (Array.isArray(data)) return data;
    if (typeof data === "string") {
      try {
        return JSON.parse(data);
      } catch {
        return [];
      }
    }
    return [];
  }, [formData]);

  const setRepeaterData = useCallback((fieldName: string, data: unknown[]) => {
    setValue(fieldName, data);
  }, [setValue]);

  const addRepeaterRow = useCallback((fieldName: string, row: Record<string, unknown>) => {
    const current = getRepeaterData(fieldName);
    setValue(fieldName, [...current, row]);
  }, [getRepeaterData, setValue]);

  const updateRepeaterRow = useCallback((fieldName: string, index: number, row: Record<string, unknown>) => {
    const current = getRepeaterData(fieldName) as Record<string, unknown>[];
    const updated = [...current];
    updated[index] = { ...updated[index], ...row };
    setValue(fieldName, updated);
  }, [getRepeaterData, setValue]);

  const deleteRepeaterRow = useCallback((fieldName: string, index: number) => {
    const current = getRepeaterData(fieldName);
    const updated = current.filter((_, i) => i !== index);
    setValue(fieldName, updated);
  }, [getRepeaterData, setValue]);

  // ===== Context 값 =====

  const contextValue = useMemo<V2FormContextValue>(() => ({
    // 기존 기능
    formData,
    fieldStates,
    getValue,
    setValue,
    setValues,
    evaluateCondition,
    getCascadingFilter,
    registerField,
    unregisterField,
    
    // 새로운 기능
    originalData,
    status,
    errors,
    submit,
    reset,
    validate,
    clear,
    setInitialData,
    setFieldError,
    clearFieldError,
    clearAllErrors,
    getChangedFields,
    hasChanges,
    getRepeaterData,
    setRepeaterData,
    addRepeaterRow,
    updateRepeaterRow,
    deleteRepeaterRow,
  }), [
    formData,
    fieldStates,
    getValue,
    setValue,
    setValues,
    evaluateCondition,
    getCascadingFilter,
    registerField,
    unregisterField,
    originalData,
    status,
    errors,
    submit,
    reset,
    validate,
    clear,
    setInitialData,
    setFieldError,
    clearFieldError,
    clearAllErrors,
    getChangedFields,
    hasChanges,
    getRepeaterData,
    setRepeaterData,
    addRepeaterRow,
    updateRepeaterRow,
    deleteRepeaterRow,
  ]);

  return (
    <V2FormContext.Provider value={contextValue}>
      {children}
    </V2FormContext.Provider>
  );
}

// ===== 커스텀 훅 =====

/**
 * V2Form 컨텍스트 사용 (Context가 없으면 에러)
 */
export function useV2Form(): V2FormContextValue {
  const context = useContext(V2FormContext);
  if (!context) {
    throw new Error("useV2Form must be used within V2FormProvider");
  }
  return context;
}

/**
 * V2Form 컨텍스트 사용 (Context가 없어도 에러 안 남, null 반환)
 * 레거시 호환성을 위해 사용
 */
export function useV2FormOptional(): V2FormContextValue | null {
  return useContext(V2FormContext);
}

/**
 * 개별 필드 훅 - 조건부 상태와 값을 한 번에 관리
 */
export function useV2Field(
  fieldId: string,
  conditional?: ConditionalConfig
): {
  value: unknown;
  setValue: (value: unknown) => void;
  visible: boolean;
  disabled: boolean;
  error?: FieldError;
} {
  const { getValue, setValue, evaluateCondition, errors } = useV2Form();
  
  const value = getValue(fieldId);
  const { visible, disabled } = evaluateCondition(fieldId, conditional);
  const error = errors.find(e => e.fieldId === fieldId);
  
  const handleSetValue = useCallback((newValue: unknown) => {
    setValue(fieldId, newValue);
  }, [fieldId, setValue]);
  
  return {
    value,
    setValue: handleSetValue,
    visible,
    disabled,
    error,
  };
}

/**
 * 연쇄 선택 훅 - 부모 필드 값에 따라 옵션 필터링
 */
export function useCascadingOptions<T extends { parentValue?: unknown }>(
  options: T[],
  cascading?: CascadingConfig
): T[] {
  const { getCascadingFilter } = useV2Form();
  
  if (!cascading) return options;
  
  const parentValue = getCascadingFilter(cascading);
  
  if (parentValue === undefined || parentValue === null || parentValue === "") {
    return [];
  }
  
  return options.filter(opt => opt.parentValue === parentValue);
}

/**
 * 폼 액션 훅 - 저장/검증/초기화 등 액션에만 접근
 */
export function useFormActions() {
  const { submit, reset, validate, clear, hasChanges, status, errors } = useV2Form();
  
  return {
    submit,
    reset,
    validate,
    clear,
    hasChanges,
    isSubmitting: status.isSubmitting,
    isValidating: status.isValidating,
    isDirty: status.isDirty,
    isValid: status.isValid,
    errors,
  };
}

/**
 * 리피터 데이터 훅 - 특정 리피터 필드 관리
 */
export function useRepeaterField<T extends Record<string, unknown> = Record<string, unknown>>(
  fieldName: string
) {
  const { 
    getRepeaterData, 
    setRepeaterData, 
    addRepeaterRow, 
    updateRepeaterRow, 
    deleteRepeaterRow 
  } = useV2Form();
  
  const data = getRepeaterData(fieldName) as T[];
  
  return {
    data,
    setData: (newData: T[]) => setRepeaterData(fieldName, newData),
    addRow: (row: T) => addRepeaterRow(fieldName, row),
    updateRow: (index: number, row: Partial<T>) => updateRepeaterRow(fieldName, index, row as Record<string, unknown>),
    deleteRow: (index: number) => deleteRepeaterRow(fieldName, index),
    count: data.length,
  };
}

export default V2FormContext;
