import React, { useEffect, useState } from 'react';

import { useAppStateContext } from '../../context/user.data.context';
import {
  improvePrompt,
  submitBulkFromContentCheck,
} from '../../service/content-generator/content-generator.service';
import type {
  BulkFromContentCheckRequest,
  ContentGenerateFields,
  FieldPrompts,
} from '../../service/content-generator/content-generator.interface';
import {
  CREATIVITY_OPTIONS,
  FAQ_COUNT_OPTIONS,
  TONE_OPTIONS,
} from '../../lib/catalog-action-options';

/** Which field gets generated / steered; mirrors the bulk field keys. */
type FieldPromptKey = keyof ContentGenerateFields;

/** Which bulk operation runs across the audited products. */
type BulkOperation = 'fields' | 'gap' | 'faq';

const OPERATION_OPTIONS: ReadonlyArray<{
  value: BulkOperation;
  label: string;
}> = [
  {
    value: 'fields',
    label: 'Rewrite fields (titles / descriptions / tags / FAQ)',
  },
  { value: 'gap', label: 'Add missing info to descriptions' },
  { value: 'faq', label: 'Generate FAQ' },
];

const OPERATION_HELP: Record<BulkOperation, string> = {
  fields:
    'Rewrites the fields you select for every audited product. Use this to refresh weak titles and descriptions or to add tags / FAQ.',
  gap: 'Keeps each existing description and only adds the facts it is missing (specs, dimensions, materials, compatibility, use-cases). Nothing useful gets thrown away.',
  faq: 'Writes a shopper-facing FAQ for every product from its existing description, using the same FAQ engine as the Content Generator.',
};

// Default directive for the "add missing" operation. The content-gen pipeline
// rewrites a field by default, so without this it would replace the whole
// description instead of topping it up. Sent as the descriptions prompt when
// the merchant does not write their own.
const GAP_DIRECTIVE =
  'Keep the existing description and only add the information it is missing. Append the missing buyer-relevant facts, specifications, dimensions, materials, compatibility, and use-cases a shopper or AI assistant would need. Do not rewrite or repeat what is already there, and never invent details that are not supported by the product data.';

const FIELD_META: ReadonlyArray<{
  key: FieldPromptKey;
  label: string;
  placeholder: string;
}> = [
  {
    key: 'titles',
    label: 'Titles',
    placeholder:
      'Optional: how titles should read (length, what to lead with, what to include)...',
  },
  {
    key: 'descriptions',
    label: 'Descriptions',
    placeholder: 'Optional: structure, sections, what to emphasise, length...',
  },
  {
    key: 'tags',
    label: 'Tags',
    placeholder: 'Optional: how many tags, what kind, formatting...',
  },
  {
    key: 'faq',
    label: 'FAQ (Frequently Asked Questions)',
    placeholder: 'Optional: how many questions, what topics to cover...',
  },
];

const SELECT_CLASS =
  'block w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-sm focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900';
const TEXTAREA_CLASS =
  'block w-full rounded-md border-gray-300 px-3 py-2 text-sm placeholder:text-gray-400 focus:border-gray-900 focus:outline-none focus:ring-1 focus:ring-gray-900';

/** Props for {@link BulkImproveModal}. */
interface BulkImproveModalProps {
  open: boolean;
  onOpenChange: (next: boolean) => void;
  /** Content-check job whose products the bulk run covers. */
  jobId: string;
  /** Audit's detected language, used by the per-field "Enhance with AI" call. */
  language: string;
  /** When set, scope the run to this single audited SKU. */
  sku?: string;
  /** Display name for the single-SKU scope. */
  productName?: string;
}

/**
 * "Bulk improve" settings modal for the catalog-quality page. The merchant
 * picks an operation (rewrite chosen fields, add missing info to descriptions,
 * or generate FAQ) across every audited product, optionally writing a master
 * instruction (with "Enhance with AI"), then submits to the bulk endpoint. The
 * resulting file is emailed, so success here is "job started", not inline
 * content.
 *
 * @param {BulkImproveModalProps} props - Modal config.
 * @return {JSX.Element | null} The modal, or null while closed.
 */
const BulkImproveModal = ({
  open,
  onOpenChange,
  jobId,
  language,
  sku,
  productName,
}: BulkImproveModalProps): JSX.Element | null => {
  const { clientId } = useAppStateContext();

  const [operation, setOperation] = useState<BulkOperation>('fields');
  const [fields, setFields] = useState<ContentGenerateFields>({
    titles: true,
    descriptions: true,
    tags: false,
    faq: false,
  });
  const [fieldPrompts, setFieldPrompts] = useState<Partial<FieldPrompts>>({});
  const [tone, setTone] = useState<string>('professional');
  const [customTone, setCustomTone] = useState<string>('');
  const [temperature, setTemperature] = useState<string>('0.7');
  const [faqInDescription, setFaqInDescription] = useState<boolean>(true);
  const [faqCount, setFaqCount] = useState<string>('3');
  const [improvingField, setImprovingField] = useState<FieldPromptKey | null>(
    null
  );
  const [submitting, setSubmitting] = useState<boolean>(false);
  const [submitted, setSubmitted] = useState<boolean>(false);
  const [submitError, setSubmitError] = useState<string | null>(null);

  const noFieldsSelected =
    !fields.titles && !fields.descriptions && !fields.tags && !fields.faq;
  // Only the field-rewrite operation can be "empty"; gap/faq always have a target.
  const submitDisabled =
    submitting || (operation === 'fields' && noFieldsSelected);

  // Reset the success / error state every time the modal is reopened so a fresh
  // run starts from the form, not the "job started" confirmation.
  useEffect(() => {
    if (open) {
      setSubmitted(false);
      setSubmitError(null);
    }
  }, [open]);

  useEffect(() => {
    if (!open) return undefined;
    const handleKey = (event: KeyboardEvent): void => {
      if (event.key === 'Escape' && !submitting) onOpenChange(false);
    };
    window.addEventListener('keydown', handleKey);

    return () => window.removeEventListener('keydown', handleKey);
  }, [open, submitting, onOpenChange]);

  const handleFieldPromptChange = (
    field: FieldPromptKey,
    next: string
  ): void => {
    setFieldPrompts(prev => ({ ...prev, [field]: next }));
  };

  const handleImprovePrompt = async (field: FieldPromptKey): Promise<void> => {
    if (!clientId) return;
    const current = (fieldPrompts[field] || '').trim();
    if (!current) return;
    setImprovingField(field);
    try {
      const response = await improvePrompt(
        current,
        field,
        language || 'en',
        clientId
      );
      const improved = response?.data?.improved_prompt;
      if (improved) {
        setFieldPrompts(prev => ({ ...prev, [field]: improved }));
      }
    } catch {
      /* keep the user's text on failure */
    } finally {
      setImprovingField(null);
    }
  };

  const buildPayload = (): BulkFromContentCheckRequest => {
    const base = {
      tone,
      custom_tone: tone === 'custom' ? customTone : undefined,
      temperature: Number(temperature),
      sku,
    };
    if (operation === 'gap') {
      return {
        ...base,
        generate_fields: {
          titles: false,
          descriptions: true,
          tags: false,
          faq: false,
        },
        field_prompts: {
          descriptions:
            (fieldPrompts.descriptions || '').trim() || GAP_DIRECTIVE,
        },
      };
    }
    if (operation === 'faq') {
      const custom = (fieldPrompts.faq || '').trim();

      return {
        ...base,
        generate_fields: {
          titles: false,
          descriptions: false,
          tags: false,
          faq: true,
        },
        field_prompts: custom ? { faq: custom } : undefined,
        // No description is generated by this operation, so the Q&A has no body
        // to ride in and comes back as its own CSV column.
        faq_in_description: false,
        faq_count: Number(faqCount),
      };
    }

    return {
      ...base,
      generate_fields: fields,
      field_prompts: fieldPrompts,
      faq_in_description: fields.faq
        ? faqInDescription && fields.descriptions
        : undefined,
      faq_count: fields.faq ? Number(faqCount) : undefined,
    };
  };

  const handleSubmit = async (): Promise<void> => {
    if (!clientId || submitDisabled) return;
    setSubmitting(true);
    setSubmitError(null);
    try {
      const response = await submitBulkFromContentCheck(
        jobId,
        buildPayload(),
        clientId
      );
      if (response?.errors || !response?.data?.job_id) {
        setSubmitError(
          response?.message ??
            'Could not start the bulk job. A content job may already be running.'
        );

        return;
      }
      setSubmitted(true);
    } catch {
      setSubmitError('Could not start the bulk job. Try again.');
    } finally {
      setSubmitting(false);
    }
  };

  if (!open) return null;

  return (
    <div className="fixed inset-0 z-[1000] flex items-center justify-center p-4">
      <div
        className="absolute inset-0 bg-black/40"
        onClick={() => {
          if (!submitting) onOpenChange(false);
        }}
      />
      <div
        role="dialog"
        aria-modal="true"
        aria-label={sku ? 'Improve product' : 'Bulk improve catalog'}
        className="relative z-10 max-h-[85vh] w-full max-w-3xl overflow-y-auto rounded-xl bg-white p-6 shadow-xl"
      >
        <div>
          <h3 className="text-base font-semibold text-gray-900">
            {sku ? 'Improve product' : 'Bulk improve catalog'}
          </h3>
          <p className="mt-1 text-sm text-gray-500">
            {sku
              ? `Run one operation on ${productName || sku}. The finished file is sent to your email.`
              : 'Run one operation across every product in this audit. The finished file is sent to your email to batch-upload to your store.'}
          </p>
        </div>

        {submitted ? (
          <div className="flex flex-col items-center gap-3 py-10 text-center">
            <p className="text-sm font-medium text-gray-900">
              Bulk job started.
            </p>
            <p className="max-w-sm text-sm text-gray-500">
              We are generating content for the audited products. The results
              will arrive in your email as a downloadable file you can batch
              upload to your store.
            </p>
            <button
              type="button"
              onClick={() => onOpenChange(false)}
              className="mt-2 rounded-md bg-gray-900 px-5 py-2 text-sm font-medium text-white hover:bg-gray-800"
            >
              Done
            </button>
          </div>
        ) : (
          <>
            <div className="mt-5 space-y-5">
              <div className="space-y-2">
                <label className="block text-sm font-medium text-gray-900">
                  What to generate
                </label>
                <select
                  value={operation}
                  onChange={event =>
                    setOperation(event.target.value as BulkOperation)
                  }
                  className={SELECT_CLASS}
                >
                  {OPERATION_OPTIONS.map(option => (
                    <option key={option.value} value={option.value}>
                      {option.label}
                    </option>
                  ))}
                </select>
                <p className="text-xs text-gray-500">
                  {OPERATION_HELP[operation]}
                </p>
              </div>

              <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
                <div className="space-y-2">
                  <label className="block text-sm font-medium text-gray-900">
                    Tone
                  </label>
                  <select
                    value={tone}
                    onChange={event => setTone(event.target.value)}
                    className={SELECT_CLASS}
                  >
                    {TONE_OPTIONS.map(option => (
                      <option key={option.value} value={option.value}>
                        {option.label}
                      </option>
                    ))}
                  </select>
                </div>
                <div className="space-y-2">
                  <label className="block text-sm font-medium text-gray-900">
                    Creativity
                  </label>
                  <select
                    value={temperature}
                    onChange={event => setTemperature(event.target.value)}
                    className={SELECT_CLASS}
                  >
                    {CREATIVITY_OPTIONS.map(option => (
                      <option key={option.value} value={option.value}>
                        {option.label}
                      </option>
                    ))}
                  </select>
                </div>
              </div>

              {tone === 'custom' && (
                <div className="space-y-2">
                  <label className="block text-sm font-medium text-gray-900">
                    Custom tone description
                  </label>
                  <textarea
                    value={customTone}
                    onChange={event => setCustomTone(event.target.value)}
                    placeholder="Describe the voice you want across all generated content..."
                    maxLength={500}
                    rows={2}
                    className={TEXTAREA_CLASS}
                  />
                </div>
              )}

              <hr className="border-gray-100" />

              {operation === 'fields' && (
                <div className="space-y-3">
                  <h4 className="text-sm font-semibold text-gray-900">
                    Content to generate
                  </h4>
                  <p className="text-sm text-gray-500">
                    Pick the fields to generate. Leave a prompt empty to use the
                    default AI behaviour, or write your own master instruction.
                  </p>

                  {FIELD_META.map(meta => (
                    <div key={meta.key} className="space-y-2">
                      <label className="flex cursor-pointer items-center gap-2">
                        <input
                          type="checkbox"
                          checked={fields[meta.key]}
                          onChange={event =>
                            setFields(prev => ({
                              ...prev,
                              [meta.key]: event.target.checked,
                            }))
                          }
                          className="h-4 w-4 rounded border-gray-300 text-[#B7007C] focus:ring-[#B7007C]"
                        />
                        <span className="text-sm font-medium text-gray-900">
                          {meta.label}
                        </span>
                      </label>
                      {fields[meta.key] && (
                        <FieldPromptSection
                          field={meta.key}
                          placeholder={meta.placeholder}
                          value={fieldPrompts[meta.key] || ''}
                          onChange={handleFieldPromptChange}
                          onImprove={handleImprovePrompt}
                          improving={improvingField === meta.key}
                        />
                      )}
                      {meta.key === 'faq' && fields.faq && (
                        <div className="space-y-3 pl-7">
                          <FaqCount value={faqCount} onChange={setFaqCount} />
                          <FaqPlacement
                            value={faqInDescription}
                            onChange={setFaqInDescription}
                            descriptionsEnabled={fields.descriptions}
                          />
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              )}

              {operation === 'gap' && (
                <div className="space-y-2">
                  <h4 className="text-sm font-semibold text-gray-900">
                    Add missing info
                  </h4>
                  <p className="text-sm text-gray-500">
                    Want to steer it? Write an optional instruction below (for
                    example, which specs matter most for your products). Leave
                    it empty to top up each description with whatever it is
                    missing. &quot;Enhance with AI&quot; rewrites your note into
                    a sharper instruction.
                  </p>
                  <FieldPromptSection
                    field="descriptions"
                    placeholder="Optional: e.g. always include dimensions, material, and what's in the box..."
                    value={fieldPrompts.descriptions || ''}
                    onChange={handleFieldPromptChange}
                    onImprove={handleImprovePrompt}
                    improving={improvingField === 'descriptions'}
                  />
                </div>
              )}

              {operation === 'faq' && (
                <div className="space-y-2">
                  <h4 className="text-sm font-semibold text-gray-900">
                    Generate FAQ
                  </h4>
                  <p className="text-sm text-gray-500">
                    Want to steer it? Write an optional instruction below (for
                    example, the topics or number of questions to cover). Leave
                    it empty to use the default FAQ engine, which writes the
                    real questions shoppers ask. &quot;Enhance with AI&quot;
                    rewrites your note into a sharper instruction.
                  </p>
                  <FieldPromptSection
                    field="faq"
                    placeholder="Optional: e.g. focus on fit, care, and compatibility; 4-6 questions..."
                    value={fieldPrompts.faq || ''}
                    onChange={handleFieldPromptChange}
                    onImprove={handleImprovePrompt}
                    improving={improvingField === 'faq'}
                  />
                  <div className="space-y-3 pl-7">
                    <FaqCount value={faqCount} onChange={setFaqCount} />
                    {/* This operation rewrites nothing but the FAQ, so there is
                        no description body to append to: the Q&A always ships
                        as its own CSV column. */}
                    <p className="text-xs text-gray-500">
                      The FAQ arrives in its own column in the CSV.
                    </p>
                  </div>
                </div>
              )}

              {submitError && (
                <p className="text-sm text-red-600" role="alert">
                  {submitError}
                </p>
              )}
            </div>

            <div className="mt-6 flex justify-end gap-3 border-t border-gray-100 pt-4">
              <button
                type="button"
                onClick={() => onOpenChange(false)}
                disabled={submitting}
                className="rounded-md border border-gray-200 bg-white px-5 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
              >
                Cancel
              </button>
              <button
                type="button"
                onClick={handleSubmit}
                disabled={submitDisabled}
                className="rounded-md bg-[#B7007C] px-5 py-2 text-sm font-semibold text-white hover:bg-[#900063] disabled:opacity-60"
              >
                {submitting ? 'Starting…' : 'Start bulk job'}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
};

/** Props for {@link FieldPromptSection}. */
interface FieldPromptSectionProps {
  field: FieldPromptKey;
  placeholder: string;
  value: string;
  onChange: (field: FieldPromptKey, next: string) => void;
  onImprove: (field: FieldPromptKey) => void;
  improving: boolean;
}

/**
 * A single optional master-instruction textarea with an "Enhance with AI"
 * button, mirroring the Prompt Templates field editor.
 *
 * @param {FieldPromptSectionProps} props - Field config + handlers.
 * @return {JSX.Element} The field block.
 */
const FieldPromptSection = ({
  field,
  placeholder,
  value,
  onChange,
  onImprove,
  improving,
}: FieldPromptSectionProps): JSX.Element => {
  return (
    <div className="space-y-1.5 pl-7">
      <div className="flex items-center justify-end">
        <button
          type="button"
          onClick={() => onImprove(field)}
          disabled={improving || !value.trim()}
          className="text-[10px] font-semibold text-gray-600 hover:text-gray-900 disabled:cursor-not-allowed disabled:opacity-50"
        >
          {improving ? 'Enhancing…' : '✨ Enhance with AI'}
        </button>
      </div>
      <textarea
        value={value}
        onChange={event => onChange(field, event.target.value)}
        placeholder={placeholder}
        rows={2}
        maxLength={4500}
        className={TEXTAREA_CLASS}
      />
    </div>
  );
};

/** Props for {@link FaqCount}. */
interface FaqCountProps {
  value: string;
  onChange: (next: string) => void;
}

/** "How many questions" picker (1-10) shared by the FAQ operations. */
const FaqCount = ({ value, onChange }: FaqCountProps): JSX.Element => {
  return (
    <div className="space-y-2">
      <label className="block text-sm font-medium text-gray-900">
        How many questions
      </label>
      <select
        value={value}
        onChange={event => onChange(event.target.value)}
        className={SELECT_CLASS}
      >
        {FAQ_COUNT_OPTIONS.map(count => (
          <option key={count} value={count}>
            {count}
          </option>
        ))}
      </select>
    </div>
  );
};

/** Props for {@link FaqPlacement}. */
interface FaqPlacementProps {
  value: boolean;
  onChange: (next: boolean) => void;
  descriptionsEnabled: boolean;
}

/** FAQ placement picker for the field-rewrite operation. */
const FaqPlacement = ({
  value,
  onChange,
  descriptionsEnabled,
}: FaqPlacementProps): JSX.Element => {
  return (
    <div className="space-y-2">
      <label className="block text-sm font-medium text-gray-900">
        FAQ placement
      </label>
      <select
        value={value && descriptionsEnabled ? 'in_description' : 'separate'}
        onChange={event => onChange(event.target.value === 'in_description')}
        className={SELECT_CLASS}
      >
        <option value="in_description" disabled={!descriptionsEnabled}>
          Include in description (Recommended)
        </option>
        <option value="separate">Separate FAQ column</option>
      </select>
      {!descriptionsEnabled && (
        <p className="text-xs text-gray-500">
          Descriptions are off, so the FAQ gets its own column in the CSV.
        </p>
      )}
    </div>
  );
};

export default BulkImproveModal;
