import React, { useEffect, useMemo, useState } from 'react';
import { FileText, Mail, Phone } from 'lucide-react';
import { BaseModal, Button, DateInput, useErrorToast, useSuccessToast } from '@nexuscrm/salesforce-crm-standard-frontend/platform/components/ui';
import {
  crmActivityTimelineSurface,
  hasCRMActivityTimelineContext,
  isCRMActivityRelationPrefillField,
  resolveCRMActivityRelationFieldFromRecord,
  type CRMActivityRelationField,
} from './activity-timeline-surface';
import { useObjectMetadata } from './platform/infrastructure/api/objectMetadataHooks';

export interface CrmTaskActivityActionInput {
  name: string;
  label?: string;
  type: string;
  required?: boolean;
  defaulted?: boolean;
  defaultValue?: unknown;
  prefillSourceFieldAPIName?: string;
  targetObject?: string;
  targetFieldAPIName?: string;
  uiMode?: string;
}

export interface CrmTaskActivityAction {
  name: string;
  label: string;
  endpoint?: string;
  inputs?: readonly CrmTaskActivityActionInput[];
}

export interface CrmTaskActivityPicklistValue {
  value: string;
  active?: boolean;
}

export interface CrmTaskActivityField {
  name: string;
  type?: string;
  picklistValues?: readonly CrmTaskActivityPicklistValue[];
}

export interface CrmTaskActivityObjectMetadata {
  name: string;
  fields?: readonly CrmTaskActivityField[];
}

export type CrmTaskActivityRecord = Record<string, unknown>;

export interface CrmTaskActivityHost {
  refreshRecord: () => void;
}

export interface CrmTaskActivityApi {
  executeStandardAction: (
    actionEndpoint: string,
    inputs: Record<string, unknown>[],
  ) => Promise<Record<string, unknown>>;
}

export interface CrmTaskActivityQuickCreateModalProps {
  isOpen: boolean;
  onClose: () => void;
  action: CrmTaskActivityAction;
  record: CrmTaskActivityRecord;
  objectMetadata: CrmTaskActivityObjectMetadata;
  host: CrmTaskActivityHost;
  api: CrmTaskActivityApi;
  currentUserId?: string | null;
}

interface FormField {
  key: string;
  label: string;
  type: 'text' | 'date' | 'textarea' | 'select';
  required?: boolean;
  options?: string[];
}

const ACTION_ICONS: Record<string, typeof Phone> = {
  taskCall: Phone,
  taskEmail: Mail,
};

export function hasActivityTimelineContext(record: CrmTaskActivityRecord): boolean {
  return hasCRMActivityTimelineContext(crmActivityTimelineSurface, record);
}

/**
 * Whether the activity quick-create can operate for `record`. True on the
 * Activity Timeline (its surface injects a relation-field hint onto the record)
 * AND when the action is invoked from a record-page header standard action,
 * which passes the raw host record with no hint: the relation field and
 * WhatId/WhoId resolve from the object + record.Id (see resolveActivityRelationField
 * / buildTaskActivityInitialValues / buildTaskActivityActionPayload), so a present
 * record Id is sufficient context outside the timeline. Where the header action
 * appears is already gated by its layout placement and the action's targetObjects.
 */
export function canQuickCreateFromRecord(record: CrmTaskActivityRecord): boolean {
  if (hasActivityTimelineContext(record)) {
    return true;
  }
  return typeof record.Id === 'string' && record.Id.trim() !== '';
}

export function resolveActivityRelationField(
  record: CrmTaskActivityRecord,
  objectApiName: string,
): CRMActivityRelationField {
  return resolveCRMActivityRelationFieldFromRecord(
    crmActivityTimelineSurface,
    record,
    objectApiName,
  );
}

/**
 * The object an activity quick-create action writes to is declared by its inputs'
 * `targetObject` (Event for the Engagement action, Task for Log a Call / Email).
 * Picklist options and field shapes must be resolved against that object's
 * metadata, not the host record object — otherwise target-object picklists such
 * as Event.Contact_Role__c render with no options. Falls back to 'Task' for legacy
 * task actions whose inputs omit an explicit targetObject.
 */
export function resolveActivityTargetObjectApiName(
  inputs: readonly CrmTaskActivityActionInput[] | undefined,
): string {
  const withTarget = (inputs ?? []).find(
    input => input.targetObject && input.targetObject !== '$Input',
  );
  return withTarget?.targetObject || 'Task';
}

function normalizeActionInputField(input: CrmTaskActivityActionInput): FormField | null {
  if (input.uiMode === 'hidden') {
    return null;
  }

  const fieldType =
    input.type === 'textarea'
      ? 'textarea'
      : input.type === 'date'
        ? 'date'
        : input.type === 'picklist'
          ? 'select'
          : 'text';

  return {
    key: input.name,
    label: input.label || input.targetFieldAPIName || input.name,
    type: fieldType,
    required: !!input.required && !input.defaulted,
  };
}

function getPicklistOptions(field?: CrmTaskActivityField): string[] | null {
  if (!field || field.type !== 'picklist' || !field.picklistValues?.length) {
    return null;
  }

  const options = field.picklistValues
    .filter(option => option.active !== false)
    .map(option => option.value)
    .filter(Boolean);

  return options.length > 0 ? [''].concat(options) : null;
}

function stringifyDefaultValue(value: unknown): string {
  if (value === undefined || value === null) {
    return '';
  }
  return String(value);
}

function isCurrentRecordRelationPrefill(
  input: CrmTaskActivityActionInput,
  record: CrmTaskActivityRecord,
  objectApiName: string,
): boolean {
  if (!isCRMActivityRelationPrefillField(crmActivityTimelineSurface, input.prefillSourceFieldAPIName)) {
    return true;
  }
  if (input.prefillSourceFieldAPIName !== resolveActivityRelationField(record, objectApiName)) {
    return false;
  }
  const recordId = typeof record.Id === 'string' ? record.Id : '';
  if (recordId === '') {
    return false;
  }
  const value = record[input.prefillSourceFieldAPIName];
  if (value === undefined || value === null || value === '') {
    return true;
  }
  return String(value) === recordId;
}

function isClientSeededHiddenValue(
  input: CrmTaskActivityActionInput,
  formData: Record<string, string>,
  record: CrmTaskActivityRecord,
  objectApiName: string,
): boolean {
  const value = formData[input.name] ?? '';
  if (value === '') {
    return false;
  }
  if (input.prefillSourceFieldAPIName) {
    return isCurrentRecordRelationPrefill(input, record, objectApiName);
  }
  return input.name === crmActivityTimelineSurface.quickCreate.ownerField;
}

export function buildTaskActivityInitialValues(
  actionInputs: CrmTaskActivityActionInput[],
  record: CrmTaskActivityRecord,
  objectApiName: string,
  currentUserId?: string | null,
): Record<string, string> {
  const defaults: Record<string, string> = {};

  actionInputs.forEach(input => {
    if (input.defaultValue !== undefined) {
      defaults[input.name] = stringifyDefaultValue(input.defaultValue);
      return;
    }
    if (input.prefillSourceFieldAPIName) {
      if (!isCurrentRecordRelationPrefill(input, record, objectApiName)) {
        return;
      }
      const value = record[input.prefillSourceFieldAPIName];
      if (value !== undefined && value !== null && value !== '') {
        defaults[input.name] = String(value);
        return;
      }
      defaults[input.name] = String(record.Id ?? '');
      return;
    }
    if (input.name === crmActivityTimelineSurface.quickCreate.ownerField && currentUserId) {
      defaults[input.name] = currentUserId;
    }
  });

  return defaults;
}

export function buildTaskActivityActionPayload(
  actionInputs: CrmTaskActivityActionInput[],
  formData: Record<string, string>,
  touchedFields: Record<string, boolean>,
  record: CrmTaskActivityRecord,
  objectApiName: string,
): Record<string, unknown> {
  const payload: Record<string, unknown> = {
    recordId: record.Id,
  };

  actionInputs.forEach(input => {
    if (input.name === 'recordId') {
      return;
    }
    if (input.prefillSourceFieldAPIName && !isCurrentRecordRelationPrefill(input, record, objectApiName)) {
      return;
    }

    const value = formData[input.name] ?? '';
    const touched = !!touchedFields[input.name];

    if (!touched) {
      if (isClientSeededHiddenValue(input, formData, record, objectApiName)) {
        payload[input.name] = value;
        return;
      }
      if (input.required && !input.defaulted) {
        payload[input.name] = value;
      }
      return;
    }

    if (value === '') {
      if (input.required) {
        return;
      }
      payload[input.name] = null;
      return;
    }

    payload[input.name] = value;
  });

  return payload;
}

export const CrmTaskActivityQuickCreateModal: React.FC<CrmTaskActivityQuickCreateModalProps> = ({
  isOpen,
  onClose,
  action,
  record,
  objectMetadata,
  host,
  api,
  currentUserId,
}) => {
  const showSuccess = useSuccessToast();
  const showError = useErrorToast();
  const [formData, setFormData] = useState<Record<string, string>>({});
  const [touchedFields, setTouchedFields] = useState<Record<string, boolean>>({});
  const [saving, setSaving] = useState(false);
  const canQuickCreate = canQuickCreateFromRecord(record);

  const actionInputs = useMemo(
    () => (action.inputs ?? []).filter(input => input.name !== 'recordId'),
    [action.inputs],
  );
  // Resolve field metadata against the object this action writes to (Event for
  // Engagement, Task for Log a Call / Email) rather than the host record object,
  // so target-object picklists such as Event.Contact_Role__c render their options.
  const targetObjectApiName = resolveActivityTargetObjectApiName(action.inputs);
  const { metadata: targetMetadata } = useObjectMetadata(targetObjectApiName);
  const targetFieldMap = useMemo(() => {
    const fields = (targetMetadata?.fields ?? []) as unknown as readonly CrmTaskActivityField[];
    return new Map(fields.map(field => [field.name, field]));
  }, [targetMetadata?.fields]);
  const inputByName = useMemo(
    () => new Map(actionInputs.map(input => [input.name, input])),
    [actionInputs],
  );
  const visibleFields = useMemo(
    () => actionInputs.map(normalizeActionInputField).filter((field): field is FormField => field !== null),
    [actionInputs],
  );
  const resolvedFields = useMemo(() => (
    visibleFields.map(field => {
      if (field.options?.length) {
        return field;
      }

      // Look the field up by its backing object field API name, not the input
      // name — the two differ (input "Contact_Role" -> field "Contact_Role__c",
      // input "EventSubject" -> field "Subject").
      const input = inputByName.get(field.key);
      const metadataField = targetFieldMap.get(input?.targetFieldAPIName || field.key);
      const metadataOptions = getPicklistOptions(metadataField);
      if (!metadataOptions) {
        return field;
      }

      return {
        ...field,
        type: 'select' as const,
        options: metadataOptions,
      };
    })
  ), [targetFieldMap, inputByName, visibleFields]);

  useEffect(() => {
    if (!isOpen || !canQuickCreate) {
      return;
    }

    const defaults = buildTaskActivityInitialValues(
      actionInputs,
      record,
      objectMetadata.name,
      currentUserId,
    );
    setFormData(defaults);
    setTouchedFields({});
  }, [actionInputs, currentUserId, canQuickCreate, isOpen, objectMetadata.name, record]);

  const handleFieldChange = (key: string, value: string) => {
    setFormData(prev => ({ ...prev, [key]: value }));
    setTouchedFields(prev => ({ ...prev, [key]: true }));
  };

  const handleSubmit = async () => {
    if (!canQuickCreate) {
      showError('Error', 'Unable to create this activity: no record context.');
      onClose();
      return;
    }

    const missingFields = resolvedFields
      .filter(field => field.required && !formData[field.key]?.trim())
      .map(field => field.label);

    if (missingFields.length > 0) {
      showError('Validation Error', `Please fill in: ${missingFields.join(', ')}`);
      return;
    }

    setSaving(true);
    try {
      const payload = buildTaskActivityActionPayload(
        actionInputs,
        formData,
        touchedFields,
        record,
        objectMetadata.name,
      );
      await api.executeStandardAction(
        action.endpoint || `/services/data/v63.0/actions/standard/${action.name}`,
        [payload],
      );
      showSuccess(`${action.label} created successfully`);
      host.refreshRecord();
      onClose();
    } catch (err) {
      const message = err instanceof Error
        ? err.message
        : crmActivityTimelineSurface.quickCreate.fallbackErrorMessage;
      showError('Error', message);
    } finally {
      setSaving(false);
    }
  };

  const Icon = ACTION_ICONS[action.name] || FileText;

  if (!canQuickCreate) {
    return null;
  }

  return (
    <BaseModal
      isOpen={isOpen}
      onClose={onClose}
      title={action.label}
      icon={Icon}
      maxWidth="md"
      footer={(
        <div className="flex justify-end gap-3 px-6 py-4 bg-gray-50 border-t border-gray-100">
          <Button variant="secondary" onClick={onClose} disabled={saving}>
            Cancel
          </Button>
          <Button variant="primary" onClick={handleSubmit} disabled={saving}>
            {saving ? 'Saving...' : 'Save'}
          </Button>
        </div>
      )}
    >
      <div className="p-6 space-y-4">
        {resolvedFields.map(field => (
          <div key={field.key}>
            <label
              htmlFor={`task-activity-action-${field.key}`}
              className="block text-sm font-medium text-gray-700 mb-1"
            >
              {field.label}
              {field.required && <span className="text-red-500 ml-1">*</span>}
            </label>
            {field.type === 'textarea' ? (
              <textarea
                id={`task-activity-action-${field.key}`}
                value={formData[field.key] ?? ''}
                onChange={e => handleFieldChange(field.key, e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
                rows={3}
              />
            ) : field.type === 'select' ? (
              <select
                id={`task-activity-action-${field.key}`}
                value={formData[field.key] ?? ''}
                onChange={e => handleFieldChange(field.key, e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
              >
                {field.options?.map(opt => (
                  <option key={opt || '__empty__'} value={opt}>
                    {opt || '--None--'}
                  </option>
                ))}
              </select>
            ) : field.type === 'date' ? (
              <DateInput
                id={`task-activity-action-${field.key}`}
                value={formData[field.key] ?? ''}
                onChange={newValue => handleFieldChange(field.key, newValue)}
                className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 disabled:bg-gray-100 disabled:text-gray-500"
              />
            ) : (
              <input
                id={`task-activity-action-${field.key}`}
                type={field.type}
                value={formData[field.key] ?? ''}
                onChange={e => handleFieldChange(field.key, e.target.value)}
                className="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
              />
            )}
          </div>
        ))}
      </div>
    </BaseModal>
  );
};
