import { useState, useEffect } from 'react';
import type { ZinoClient } from '../../api/client';
import type { FormScreenResponse } from '../../api/types';
import { Button } from '../buttons/Button';
import { Spinner } from '../reusable/Spinner';
import {
  FileInput,
  SmartGridField,
  GeolocationInput,
  PhoneInput,
  SelectField,
  TextField,
  EmailField,
  TextAreaField,
  DateField,
  TimeField,
  WfLookupField,
  RadioField,
} from './fields';
import { ORDER_BOOKING } from '../../api/config';

export interface DynamicFormProps {
  client: ZinoClient;
  activityId: string;
  instanceId?: number | string;
  onSuccess?: () => void;
  onCancel?: () => void;
  ignorePrefill?: boolean;
}

export function DynamicForm({ client, activityId: initialActivityId, instanceId: initialInstanceId, onSuccess, onCancel, ignorePrefill }: DynamicFormProps) {
  const [currentActivityId, setCurrentActivityId] = useState(initialActivityId);
  const [currentInstanceId, setCurrentInstanceId] = useState<number | string | undefined>(initialInstanceId);
  const [chainQueue, setChainQueue] = useState<Array<{ activity_uid: string; activity_name: string }>>([]);

  useEffect(() => {
    setCurrentActivityId(initialActivityId);
    setCurrentInstanceId(initialInstanceId);
    setChainQueue([]);
  }, [initialActivityId, initialInstanceId]);

  const [schema, setSchema] = useState<FormScreenResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let mounted = true;
    setLoading(true);
    client.formSchema(currentActivityId, currentInstanceId)
      .then(res => {
        if (mounted) {
          setSchema(res);
          const defaultValues: Record<string, unknown> = {};
          if (res.field_defaults) {
            Object.entries(res.field_defaults).forEach(([fieldId, def]) => {
              if (def.value != null) {
                defaultValues[fieldId] = def.value;
              } else if (def.prefill) {
                if (def.prefill.value === 'current_date') {
                  defaultValues[fieldId] = new Date().toISOString().split('T')[0];
                } else if (def.prefill.value === 'current_time') {
                  defaultValues[fieldId] = new Date().toTimeString().split(' ')[0].substring(0, 5);
                } else if (def.prefill.value === 'current_user_id') {
                  const user = client.currentUser();
                  defaultValues[fieldId] = user ? Number(user.id) : '';
                } else {
                  defaultValues[fieldId] = def.prefill.value;
                }
              }
            });
          }
          const imageFieldIds = new Set(
            res.fields.filter(f => f.data_type === 'image' || f.data_type === 'file').map(f => f.id)
          );

          if (!ignorePrefill) {
            if (res.prefill_data) {
              Object.entries(res.prefill_data).forEach(([k, v]) => {
                if (!imageFieldIds.has(k)) defaultValues[k] = v;
              });
            } else if (res.data) {
              Object.entries(res.data).forEach(([k, v]) => {
                if (!imageFieldIds.has(k)) defaultValues[k] = v;
              });
            }
          }
          
          setValues(defaultValues);
          setLoading(false);
        }
      })
      .catch((err: any) => {
        if (mounted) {
          setError(err?.message || 'Failed to load schema');
          setLoading(false);
        }
      });
    return () => { mounted = false; };
  }, [client, currentActivityId, currentInstanceId]);

  const [values, setValues] = useState<Record<string, unknown>>({});
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);

  const handleFieldChange = (fieldId: string, newVal: unknown) => {
    setValues(prev => {
      const next = { ...prev, [fieldId]: newVal };
      
      // Auto-calculate order_details totals
      if (fieldId === 'order_details' && Array.isArray(newVal)) {
        let totalBags = 0;
        let totalKgs = 0;
        newVal.forEach(row => {
          totalBags += Number(row.bags) || 0;
          totalKgs += Number(row.row_kgs) || 0;
        });
        next['total_bags'] = totalBags;
        next['total_kgs'] = totalKgs;
      }
      
      return next;
    });
  };

  if (loading) {
    return <div className="p-8 flex justify-center"><Spinner label="Loading form..." /></div>;
  }
  if (error || !schema) {
    return <div className="p-4 text-ruby-600">Failed to load form: {error}</div>;
  }

  // Filter out disabled fields (usually server-generated IDs)
  const fields = schema.fields.filter(f => !f.properties?.disabled);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setSubmitting(true);
    setSubmitError(null);
    try {
      const payload: Record<string, unknown> = {};

      for (const f of fields) {
        const val = values[f.id];
        if (val == null) continue;

        if (f.data_type === 'phone' && typeof val === 'string') {
          const phoneNum = val.replace(/^\+91\s*/, '').trim();
          payload[f.id] = {
            dial_code: '+91',
            phone: phoneNum,
            phone_with_dial_code: `+91${phoneNum}`
          };
        } else if ((f.data_type === 'image' || f.data_type === 'file') && Array.isArray(val) && val.length > 0 && val[0] instanceof File) {
          const uploadedFiles = [];
          for (const file of val) {
            const fileMeta = await client.uploadFile(file, { activityId: currentActivityId, fieldId: f.id });
            uploadedFiles.push(fileMeta);
          }
          payload[f.id] = uploadedFiles;
        } else if ((f.data_type === 'image' || f.data_type === 'file') && val instanceof File) {
          const fileMeta = await client.uploadFile(val, { activityId: currentActivityId, fieldId: f.id });
          payload[f.id] = [fileMeta];
        } else {
          payload[f.id] = val;
        }
      }

      let res;
      if (currentInstanceId != null) {
        res = await client.performActivity(currentInstanceId, currentActivityId, payload);
      } else {
        res = await client.startInstance(currentActivityId, payload);
      }
      
      let pending = [...chainQueue];
      let chainSource = (res as any).activity_chain || schema.activity_chain || [];

      // Centralized activity chaining logic
      if (currentActivityId === ORDER_BOOKING.activities.PRODUCTIVITY_OF_VISIT.uid) {
        const actionValue = String(payload[ORDER_BOOKING.activities.PRODUCTIVITY_OF_VISIT.fields.action] || '').toLowerCase().trim();
        const normalized = actionValue.replace(/[\s_]+/g, '');
        if (normalized === 'order') {
          chainSource = [{ activity_uid: ORDER_BOOKING.activities.PLACE_ORDER.uid, activity_name: 'Place Order' }];
        } else if (normalized === 'noorder') {
          chainSource = [{ activity_uid: ORDER_BOOKING.activities.POTENTIAL_MINING.uid, activity_name: 'Potential Mining' }];
        }
      }

      const newActivities = chainSource.filter(
        (a: any) => a.activity_uid !== currentActivityId
      );

      // Remove any existing occurrences from pending to avoid duplicates
      pending = pending.filter(p => !newActivities.some(n => n.activity_uid === p.activity_uid));
      
      // Prepend the new activities for depth-first execution (nested chaining)
      pending = [...newActivities, ...pending];

      const nextActivity = pending.shift();

      if (nextActivity) {
        setChainQueue(pending);
        setCurrentActivityId(nextActivity.activity_uid);
        setCurrentInstanceId(res.instance_id ?? currentInstanceId);
      } else {
        onSuccess?.();
      }
    } catch (err: any) {
      setSubmitError(err.message || 'Failed to submit form');
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-4">
      {fields.map(f => {
        const type = f.data_type;
        const val = values[f.id];
        const isDisabled = schema.field_defaults?.[f.id]?.disabled;
        
        const renderField = () => {
          if (type === 'wf_lookup') {
            return (
              <WfLookupField
                label={f.name}
                required={f.mandatory}
                value={(val as string | number) ?? ''}
                client={client}
                config={f.properties?.wf_lookup_config || f.properties?.lookup_config}
                properties={f.properties}
                activityId={currentActivityId}
                fieldId={f.id}
                formData={values}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('select') || type.startsWith('multiselect')) {
            return (
              <SelectField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                options={f.properties?.options || []}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type === 'radio') {
            return (
              <RadioField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                options={f.properties?.options || []}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('image') || type.startsWith('file')) {
            return (
              <FileInput
                label={f.name}
                type={type}
                required={f.mandatory}
                value={val}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('grid')) {
            return (
              <SmartGridField
                label={f.name}
                columns={f.columns || []}
                value={(val as Record<string, unknown>[]) || []}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('geolocation')) {
            return (
              <GeolocationInput
                label={f.name}
                required={f.mandatory}
                value={(val as { latitude: number; longitude: number }) || null}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('phone')) {
            const phoneStr = typeof val === 'object' && val !== null ? (val as any).phone || '' : (val as string) ?? '';
            return (
              <PhoneInput
                label={f.name}
                required={f.mandatory}
                value={phoneStr}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('email')) {
            return (
              <EmailField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('textarea') || type.startsWith('text_area') || type.startsWith('longtext')) {
            return (
              <TextAreaField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('date')) {
            return (
              <DateField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          if (type.startsWith('time')) {
            return (
              <TimeField
                label={f.name}
                required={f.mandatory}
                value={(val as string) ?? ''}
                onChange={(newVal) => handleFieldChange(f.id, newVal)}
              />
            );
          }

          return (
            <TextField
              label={f.name}
              required={f.mandatory}
              type={type}
              value={(val as string) ?? ''}
              onChange={(newVal) => handleFieldChange(f.id, newVal)}
            />
          );
        };

        const content = renderField();
        return isDisabled ? (
          <fieldset key={f.id} disabled className="opacity-60 pointer-events-none">
            {content}
          </fieldset>
        ) : (
          <div key={f.id}>{content}</div>
        );
      })}

      {submitError && <div className="text-sm text-ruby-600 mt-2">{submitError}</div>}

      <div className="flex items-center justify-end gap-3 mt-4 pt-4 border-t border-border-subtle">
        {onCancel && (
          <Button type="button" variant="secondary" onClick={onCancel} disabled={submitting}>
            Cancel
          </Button>
        )}
        <Button type="submit" variant="primary" disabled={submitting}>
          {submitting ? 'Submitting...' : 'Submit'}
        </Button>
      </div>
    </form>
  );
}
