/**
 * Hook to fetch and manage DocType field configurations from Frappe
 * This enables dynamic form behavior based on Frappe's Customize Form settings
 */

import { useState, useEffect, useCallback, useMemo } from 'react';
import apiService from '../services/apiService';
import { FieldConfig, evaluateFieldState, EvaluatedFieldState } from '../utils/frappeExpressionEvaluator';

interface DocTypeMeta {
  name: string;
  fields: FieldConfig[];
  title_field?: string;
  image_field?: string;
  sort_field?: string;
  sort_order?: string;
}

interface UseDocTypeFieldConfigResult {
  fields: FieldConfig[];
  loading: boolean;
  error: string | null;
  getFieldConfig: (fieldname: string) => FieldConfig | undefined;
  getFieldState: (fieldname: string, doc: Record<string, any>) => EvaluatedFieldState;
  getVisibleFields: (doc: Record<string, any>) => FieldConfig[];
  getMandatoryFields: (doc: Record<string, any>) => FieldConfig[];
  validateDocument: (doc: Record<string, any>) => { valid: boolean; errors: Record<string, string> };
  titleField: string | null;
  refresh: () => void;
}

// Cache for doctype meta to avoid repeated API calls
const metaCache: Record<string, DocTypeMeta> = {};

export function useDocTypeFieldConfig(doctype: string): UseDocTypeFieldConfigResult {
  const [fields, setFields] = useState<FieldConfig[]>([]);
  const [titleField, setTitleField] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchMeta = useCallback(async () => {
    if (!doctype) {
      setLoading(false);
      return;
    }

    // Check cache first
    if (metaCache[doctype]) {
      setFields(metaCache[doctype].fields);
      setTitleField(metaCache[doctype].title_field || null);
      setLoading(false);
      return;
    }

    setLoading(true);
    setError(null);

    try {
      // Fetch doctype meta from Frappe
      const response = await apiService.apiCall<any>(
        `/api/method/frappe.client.get_doc?doctype=DocType&name=${encodeURIComponent(doctype)}`,
        { credentials: 'include' }
      );

      if (response?.message) {
        const meta = response.message;
        const fieldConfigs: FieldConfig[] = (meta.fields || []).map((f: any) => ({
          fieldname: f.fieldname,
          label: f.label,
          fieldtype: f.fieldtype,
          options: f.options,
          reqd: f.reqd,
          hidden: f.hidden,
          read_only: f.read_only,
          depends_on: f.depends_on,
          mandatory_depends_on: f.mandatory_depends_on,
          read_only_depends_on: f.read_only_depends_on,
          fetch_from: f.fetch_from,
          fetch_if_empty: f.fetch_if_empty,
          default: f.default,
          description: f.description,
          in_list_view: f.in_list_view,
          in_standard_filter: f.in_standard_filter,
          permlevel: f.permlevel,
          allow_on_submit: f.allow_on_submit,
        }));

        // Cache the result
        metaCache[doctype] = {
          name: doctype,
          fields: fieldConfigs,
          title_field: meta.title_field,
          image_field: meta.image_field,
          sort_field: meta.sort_field,
          sort_order: meta.sort_order,
        };

        setFields(fieldConfigs);
        setTitleField(meta.title_field || null);
      }
    } catch (err: any) {
      console.error(`Failed to fetch DocType meta for ${doctype}:`, err);
      setError(err.message || 'Failed to fetch field configuration');
      
      // Try alternative API endpoint (for customized forms)
      try {
        const customResponse = await apiService.apiCall<any>(
          `/api/resource/Customize Form?filters=[["doc_type","=","${doctype}"]]&limit=1`,
          { credentials: 'include' }
        );
        
        if (customResponse?.data?.[0]) {
          // Fetch the full customize form document
          const customDoc = await apiService.apiCall<any>(
            `/api/resource/Customize Form/${encodeURIComponent(customResponse.data[0].name)}`,
            { credentials: 'include' }
          );
          
          if (customDoc?.data?.fields) {
            const fieldConfigs: FieldConfig[] = customDoc.data.fields.map((f: any) => ({
              fieldname: f.fieldname,
              label: f.label,
              fieldtype: f.fieldtype,
              options: f.options,
              reqd: f.reqd,
              hidden: f.hidden,
              read_only: f.read_only,
              depends_on: f.depends_on,
              mandatory_depends_on: f.mandatory_depends_on,
              read_only_depends_on: f.read_only_depends_on,
              fetch_from: f.fetch_from,
              fetch_if_empty: f.fetch_if_empty,
              default: f.default,
              description: f.description,
              in_list_view: f.in_list_view,
              in_standard_filter: f.in_standard_filter,
              permlevel: f.permlevel,
              allow_on_submit: f.allow_on_submit,
            }));

            metaCache[doctype] = {
              name: doctype,
              fields: fieldConfigs,
              title_field: customDoc.data.title_field,
            };

            setFields(fieldConfigs);
            setTitleField(customDoc.data.title_field || null);
            setError(null);
          }
        }
      } catch (customErr) {
        console.warn('Customize Form fetch also failed:', customErr);
      }
    } finally {
      setLoading(false);
    }
  }, [doctype]);

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

  // Get config for a specific field
  const getFieldConfig = useCallback((fieldname: string): FieldConfig | undefined => {
    return fields.find(f => f.fieldname === fieldname);
  }, [fields]);

  // Get evaluated state for a field based on current document
  const getFieldState = useCallback((fieldname: string, doc: Record<string, any>): EvaluatedFieldState => {
    const config = getFieldConfig(fieldname);
    if (!config) {
      return { isVisible: true, isReadOnly: false, isMandatory: false };
    }
    return evaluateFieldState(config, doc);
  }, [getFieldConfig]);

  // Get all visible fields for current document state
  const getVisibleFields = useCallback((doc: Record<string, any>): FieldConfig[] => {
    return fields.filter(field => {
      const state = evaluateFieldState(field, doc);
      return state.isVisible;
    });
  }, [fields]);

  // Get all mandatory fields for current document state
  const getMandatoryFields = useCallback((doc: Record<string, any>): FieldConfig[] => {
    return fields.filter(field => {
      const state = evaluateFieldState(field, doc);
      return state.isVisible && state.isMandatory;
    });
  }, [fields]);

  // Validate document against field requirements
  const validateDocument = useCallback((doc: Record<string, any>): { valid: boolean; errors: Record<string, string> } => {
    const errors: Record<string, string> = {};
    
    for (const field of fields) {
      const state = evaluateFieldState(field, doc);
      
      if (state.isVisible && state.isMandatory) {
        const value = doc[field.fieldname];
        if (value === undefined || value === null || value === '') {
          errors[field.fieldname] = `${field.label || field.fieldname} is required`;
        }
      }
    }
    
    return {
      valid: Object.keys(errors).length === 0,
      errors
    };
  }, [fields]);

  const refresh = useCallback(() => {
    // Clear cache for this doctype
    delete metaCache[doctype];
    fetchMeta();
  }, [doctype, fetchMeta]);

  return {
    fields,
    loading,
    error,
    getFieldConfig,
    getFieldState,
    getVisibleFields,
    getMandatoryFields,
    validateDocument,
    titleField,
    refresh
  };
}

export default useDocTypeFieldConfig;

