import { useEffect, useState } from 'react';
import {
  Alert,
  Button,
  Code,
  Container,
  FileInput,
  Group,
  NumberInput,
  Paper,
  Select,
  Stack,
  Text,
  TextInput,
  Textarea,
  Title,
} from '@mantine/core';
import { notifications } from '@mantine/notifications';
import { IconAlertCircle, IconSend } from '@tabler/icons-react';
import { apiClient } from '../lib/api';
import type { WhatsAppAccountConfig } from '../types';

type MessageType =
  | 'text'
  | 'image'
  | 'video'
  | 'document'
  | 'audio'
  | 'sticker'
  | 'location'
  | 'reaction'
  | 'contacts'
  | 'interactive'
  | 'template'
  | 'flow'
  | 'catalog'
  | 'product'
  | 'product-list';

const MESSAGE_TYPES: { value: MessageType; label: string }[] = [
  { value: 'text', label: 'Text' },
  { value: 'image', label: 'Image' },
  { value: 'video', label: 'Video' },
  { value: 'document', label: 'Document' },
  { value: 'audio', label: 'Audio' },
  { value: 'sticker', label: 'Sticker' },
  { value: 'location', label: 'Location' },
  { value: 'reaction', label: 'Reaction' },
  { value: 'contacts', label: 'Contacts (JSON)' },
  { value: 'interactive', label: 'Interactive (JSON)' },
  { value: 'template', label: 'Template (JSON)' },
  { value: 'flow', label: 'Flow' },
  { value: 'catalog', label: 'Catalog' },
  { value: 'product', label: 'Single Product' },
  { value: 'product-list', label: 'Product List' },
];

function isBlank(value: string): boolean {
  return value.trim().length === 0;
}

function normalizeBase64(value: string): string {
  const trimmed = value.trim();
  const commaIndex = trimmed.indexOf(',');
  if (trimmed.startsWith('data:') && commaIndex > -1) {
    return trimmed.slice(commaIndex + 1).trim();
  }
  return trimmed;
}

function extractMimeTypeFromDataURL(value: string): string {
  const trimmed = value.trim();
  if (!trimmed.startsWith('data:')) {
    return '';
  }
  const semicolonIndex = trimmed.indexOf(';');
  const colonIndex = trimmed.indexOf(':');
  if (semicolonIndex <= colonIndex) {
    return '';
  }
  return trimmed.slice(colonIndex + 1, semicolonIndex).trim();
}

function isLikelyBase64(value: string): boolean {
  if (!value) {
    return false;
  }
  const compact = value.replace(/\s+/g, '');
  if (compact.length === 0 || compact.length % 4 !== 0) {
    return false;
  }
  return /^[A-Za-z0-9+/=]+$/.test(compact);
}

function inferMediaMimeType(
  explicitMimeType: string,
  sourceValue: string,
  messageType: MessageType,
): string {
  const trimmed = explicitMimeType.trim();
  if (trimmed) {
    return trimmed;
  }

  const inferredFromDataURL = extractMimeTypeFromDataURL(sourceValue);
  if (inferredFromDataURL) {
    return inferredFromDataURL;
  }

  switch (messageType) {
    case 'image':
      return 'image/jpeg';
    case 'video':
      return 'video/mp4';
    case 'document':
      return 'application/octet-stream';
    case 'audio':
      return 'audio/mpeg';
    case 'sticker':
      return 'image/webp';
    default:
      return '';
  }
}

function parseJSONField<T>(raw: string, label: string): T {
  try {
    return JSON.parse(raw) as T;
  } catch {
    throw new Error(`${label} must be valid JSON`);
  }
}

function getEndpoint(type: MessageType): string {
  switch (type) {
    case 'text':
      return '/api/send';
    case 'image':
      return '/api/send/image';
    case 'video':
      return '/api/send/video';
    case 'document':
      return '/api/send/document';
    case 'audio':
      return '/api/send/audio';
    case 'sticker':
      return '/api/send/sticker';
    case 'location':
      return '/api/send/location';
    case 'reaction':
      return '/api/send/reaction';
    case 'contacts':
      return '/api/send/contacts';
    case 'interactive':
      return '/api/send/interactive';
    case 'template':
      return '/api/send/template';
    case 'flow':
      return '/api/send/flow';
    case 'catalog':
      return '/api/send/catalog';
    case 'product':
      return '/api/send/product';
    case 'product-list':
      return '/api/send/product-list';
    default:
      return '/api/send';
  }
}

export default function SendMessagePage() {
  const [accounts, setAccounts] = useState<WhatsAppAccountConfig[]>([]);
  const [loadingAccounts, setLoadingAccounts] = useState(true);
  const [accountId, setAccountId] = useState('');
  const [to, setTo] = useState('');
  const [messageType, setMessageType] = useState<MessageType>('text');
  const [submitting, setSubmitting] = useState(false);

  const [text, setText] = useState('');
  const [caption, setCaption] = useState('');
  const [mimeType, setMimeType] = useState('');
  const [mediaBase64, setMediaBase64] = useState('');
  const [filename, setFilename] = useState('');
  const [latitude, setLatitude] = useState<number | ''>('');
  const [longitude, setLongitude] = useState<number | ''>('');
  const [locationName, setLocationName] = useState('');
  const [locationAddress, setLocationAddress] = useState('');
  const [messageId, setMessageId] = useState('');
  const [emoji, setEmoji] = useState('');
  const [rawJSON, setRawJSON] = useState('');
  const [flowId, setFlowId] = useState('');
  const [flowToken, setFlowToken] = useState('');
  const [flowScreenName, setFlowScreenName] = useState('');
  const [flowHeader, setFlowHeader] = useState('');
  const [flowBody, setFlowBody] = useState('');
  const [flowFooter, setFlowFooter] = useState('');
  const [catalogId, setCatalogId] = useState('');
  const [bodyText, setBodyText] = useState('');
  const [footerText, setFooterText] = useState('');
  const [headerText, setHeaderText] = useState('');
  const [productRetailerId, setProductRetailerId] = useState('');
  const [thumbnailProductRetailerId, setThumbnailProductRetailerId] = useState('');
  const [lastApiResponse, setLastApiResponse] = useState('');
  const [lastApiResponseType, setLastApiResponseType] = useState<'success' | 'error' | null>(null);

  const validateBeforeSend = (): string | null => {
    if (!accountId) {
      return 'Please select an account.';
    }

    if (isBlank(to)) {
      return 'Recipient is required.';
    }

    if (to.trim().length < 5) {
      return 'Recipient number looks too short.';
    }

    if (messageType === 'text' && isBlank(text)) {
      return 'Text message cannot be empty.';
    }

    if (
      messageType === 'image' ||
      messageType === 'video' ||
      messageType === 'document' ||
      messageType === 'audio' ||
      messageType === 'sticker'
    ) {
      const normalized = normalizeBase64(mediaBase64);
      if (!normalized) {
        return 'Base64 data is required for this message type.';
      }
      if (!isLikelyBase64(normalized)) {
        return 'Base64 data is invalid. Paste only valid base64 (raw or data URL).';
      }
      if (normalized.length < 64) {
        return 'Base64 data looks too short or incomplete.';
      }
    }

    if (messageType === 'location') {
      if (latitude === '' || longitude === '') {
        return 'Latitude and longitude are required.';
      }
      if (Number(latitude) < -90 || Number(latitude) > 90) {
        return 'Latitude must be between -90 and 90.';
      }
      if (Number(longitude) < -180 || Number(longitude) > 180) {
        return 'Longitude must be between -180 and 180.';
      }
    }

    if (messageType === 'reaction') {
      if (isBlank(messageId)) {
        return 'Message ID is required for reactions.';
      }
      if (isBlank(emoji)) {
        return 'Emoji is required for reactions.';
      }
    }

    if (messageType === 'contacts') {
      const contacts = parseJSONField<unknown[]>(rawJSON, 'Contacts');
      if (!Array.isArray(contacts) || contacts.length === 0) {
        return 'Contacts JSON must be a non-empty array.';
      }
    }

    if (messageType === 'interactive') {
      const interactive = parseJSONField<Record<string, unknown>>(rawJSON, 'Interactive payload');
      if (!interactive || Array.isArray(interactive)) {
        return 'Interactive payload must be a JSON object.';
      }
    }

    if (messageType === 'template') {
      const template = parseJSONField<{ name?: string }>(rawJSON, 'Template payload');
      if (!template || Array.isArray(template) || isBlank(template.name || '')) {
        return 'Template JSON must include a non-empty "name".';
      }
    }

    if (messageType === 'flow') {
      if (isBlank(flowId)) {
        return 'Flow ID is required.';
      }
      if (isBlank(flowBody)) {
        return 'Flow body is required.';
      }
      if (!isBlank(rawJSON)) {
        const flowData = parseJSONField<Record<string, unknown>>(
          rawJSON,
          'Flow data',
        );
        if (!flowData || Array.isArray(flowData)) {
          return 'Flow data must be a JSON object.';
        }
      }
    }

    if (messageType === 'catalog' && isBlank(bodyText)) {
      return 'Body text is required for catalog messages.';
    }

    if (messageType === 'product') {
      if (isBlank(catalogId)) {
        return 'Catalog ID is required for product messages.';
      }
      if (isBlank(productRetailerId)) {
        return 'Product Retailer ID is required.';
      }
      if (isBlank(bodyText)) {
        return 'Body text is required for product messages.';
      }
    }

    if (messageType === 'product-list') {
      if (isBlank(catalogId)) {
        return 'Catalog ID is required for product lists.';
      }
      if (isBlank(headerText) || isBlank(bodyText)) {
        return 'Header text and body text are required for product lists.';
      }
      const sections = parseJSONField<unknown[]>(rawJSON, 'Sections');
      if (!Array.isArray(sections) || sections.length === 0) {
        return 'Sections JSON must be a non-empty array.';
      }
    }

    return null;
  };

  useEffect(() => {
    const loadAccounts = async () => {
      try {
        setLoadingAccounts(true);
        const result = await apiClient.getAccountConfigs();
        const sorted = [...(result || [])].sort((a, b) =>
          a.id.localeCompare(b.id, undefined, { sensitivity: 'base' }),
        );
        setAccounts(sorted);
        if (sorted.length > 0) {
          setAccountId(sorted[0].id);
        }
      } catch (err) {
        notifications.show({
          title: 'Error',
          message: 'Failed to load accounts',
          color: 'red',
        });
        console.error(err);
      } finally {
        setLoadingAccounts(false);
      }
    };
    loadAccounts();
  }, []);

  const readFileAsDataURL = (file: File): Promise<string> =>
    new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(String(reader.result || ''));
      reader.onerror = () => reject(new Error('Failed to read file'));
      reader.readAsDataURL(file);
    });

  const handleMediaFileUpload = async (file: File | null) => {
    if (!file) {
      return;
    }

    try {
      const dataURL = await readFileAsDataURL(file);
      setMediaBase64(dataURL);

      if (isBlank(mimeType) && file.type) {
        setMimeType(file.type);
      }

      if (messageType === 'document' && isBlank(filename)) {
        setFilename(file.name);
      }

      notifications.show({
        title: 'File Loaded',
        message: `Loaded ${file.name} into Base64 data`,
        color: 'green',
      });
    } catch (err) {
      notifications.show({
        title: 'File Error',
        message: err instanceof Error ? err.message : 'Failed to read file',
        color: 'red',
      });
    }
  };

  const handleSend = async (e: React.FormEvent) => {
    e.preventDefault();

    let validationError: string | null = null;
    try {
      validationError = validateBeforeSend();
    } catch (err) {
      validationError = err instanceof Error ? err.message : 'Validation failed.';
    }

    if (validationError) {
      notifications.show({
        title: 'Validation Error',
        message: validationError,
        color: 'red',
      });
      return;
    }

    try {
      const payload: Record<string, unknown> = { account_id: accountId, to };
      const endpoint = getEndpoint(messageType);

      switch (messageType) {
        case 'text':
          payload.text = text;
          break;
        case 'image':
          payload.image_data = normalizeBase64(mediaBase64);
          payload.caption = caption.trim();
          payload.mime_type = inferMediaMimeType(mimeType, mediaBase64, messageType);
          break;
        case 'video':
          payload.video_data = normalizeBase64(mediaBase64);
          payload.caption = caption.trim();
          payload.mime_type = inferMediaMimeType(mimeType, mediaBase64, messageType);
          break;
        case 'document':
          payload.document_data = normalizeBase64(mediaBase64);
          payload.caption = caption.trim();
          payload.mime_type = inferMediaMimeType(mimeType, mediaBase64, messageType);
          payload.filename = filename.trim();
          break;
        case 'audio':
          payload.audio_data = normalizeBase64(mediaBase64);
          payload.mime_type = inferMediaMimeType(mimeType, mediaBase64, messageType);
          break;
        case 'sticker':
          payload.sticker_data = normalizeBase64(mediaBase64);
          payload.mime_type = inferMediaMimeType(mimeType, mediaBase64, messageType);
          break;
        case 'location':
          payload.latitude = Number(latitude);
          payload.longitude = Number(longitude);
          payload.name = locationName.trim();
          payload.address = locationAddress.trim();
          break;
        case 'reaction':
          payload.message_id = messageId.trim();
          payload.emoji = emoji.trim();
          break;
        case 'contacts':
          payload.contacts = parseJSONField<unknown[]>(rawJSON, 'Contacts');
          break;
        case 'interactive':
          payload.interactive = parseJSONField<Record<string, unknown>>(rawJSON, 'Interactive payload');
          break;
        case 'template':
          payload.template = parseJSONField<Record<string, unknown>>(rawJSON, 'Template payload');
          break;
        case 'flow':
          payload.flow_id = flowId.trim();
          payload.flow_token = flowToken.trim();
          payload.screen_name = flowScreenName.trim();
          payload.header = flowHeader.trim();
          payload.body = flowBody.trim();
          payload.footer = flowFooter.trim();
          payload.data = rawJSON ? parseJSONField<Record<string, unknown>>(rawJSON, 'Flow data') : {};
          break;
        case 'catalog':
          payload.body_text = bodyText.trim();
          payload.thumbnail_product_retailer_id = thumbnailProductRetailerId.trim();
          break;
        case 'product':
          payload.catalog_id = catalogId.trim();
          payload.product_retailer_id = productRetailerId.trim();
          payload.body_text = bodyText.trim();
          payload.footer_text = footerText.trim();
          break;
        case 'product-list':
          payload.catalog_id = catalogId.trim();
          payload.header_text = headerText.trim();
          payload.body_text = bodyText.trim();
          payload.footer_text = footerText.trim();
          payload.sections = parseJSONField<unknown[]>(rawJSON, 'Sections');
          break;
      }

      setSubmitting(true);
      const response = await apiClient.sendPayload(endpoint, payload);
      const responseText = JSON.stringify(response, null, 2);
      setLastApiResponse(responseText);
      setLastApiResponseType('success');
      console.log('Send API response', { endpoint, response });

      notifications.show({
        title: 'Success',
        message: 'Message sent successfully',
        color: 'green',
      });
    } catch (err) {
      const errorData = (err as { response?: { data?: unknown } })?.response?.data;
      const responseText = JSON.stringify(
        {
          error: err instanceof Error ? err.message : 'Unknown error',
          response: errorData ?? null,
        },
        null,
        2,
      );
      setLastApiResponse(responseText);
      setLastApiResponseType('error');
      console.error('Send API response (error)', err);

      notifications.show({
        title: 'Send Failed',
        message: err instanceof Error ? err.message : 'Failed to send message',
        color: 'red',
      });
      console.error(err);
    } finally {
      setSubmitting(false);
    }
  };

  const accountOptions = accounts.map((account) => ({
    value: account.id,
    label: `${account.id} (${account.type})`,
  }));

  return (
    <Container size="lg" py="xl">
      <Stack gap="lg">
        <div>
          <Title order={2}>Send Message</Title>
          <Text c="dimmed" size="sm">Choose an account, recipient, and message type to send WhatsApp messages.</Text>
        </div>

        {accounts.length === 0 && !loadingAccounts && (
          <Alert icon={<IconAlertCircle size={16} />} color="yellow" title="No Accounts">
            No WhatsApp accounts are configured yet.
          </Alert>
        )}

        <Paper withBorder p="md">
          <form onSubmit={handleSend}>
            <Stack>
              <Group grow>
                <Select
                  label="Account"
                  data={accountOptions}
                  value={accountId}
                  onChange={(value) => setAccountId(value || '')}
                  searchable
                  required
                  disabled={loadingAccounts}
                />
                <TextInput
                  label="Recipient"
                  placeholder="+1234567890"
                  value={to}
                  onChange={(e) => setTo(e.target.value)}
                  required
                />
              </Group>

              <Select
                label="Message Type"
                data={MESSAGE_TYPES}
                value={messageType}
                onChange={(value) => setMessageType((value as MessageType) || 'text')}
                required
              />

              {messageType === 'text' && (
                <Textarea label="Text" value={text} onChange={(e) => setText(e.target.value)} minRows={3} required />
              )}

              {(messageType === 'image' || messageType === 'video' || messageType === 'document' || messageType === 'audio' || messageType === 'sticker') && (
                <>
                  <FileInput
                    label="Upload File"
                    placeholder="Choose a file to populate Base64 data"
                    onChange={handleMediaFileUpload}
                    clearable
                  />
                  <Textarea
                    label="Base64 Data"
                    value={mediaBase64}
                    onChange={(e) => setMediaBase64(e.target.value)}
                    minRows={6}
                    required
                  />
                  {(messageType === 'image' || messageType === 'video' || messageType === 'document') && (
                    <TextInput label="Caption" value={caption} onChange={(e) => setCaption(e.target.value)} />
                  )}
                  <TextInput label="MIME Type" value={mimeType} onChange={(e) => setMimeType(e.target.value)} />
                  {messageType === 'document' && (
                    <TextInput label="Filename" value={filename} onChange={(e) => setFilename(e.target.value)} />
                  )}
                </>
              )}

              {messageType === 'location' && (
                <Group grow>
                  <NumberInput
                    label="Latitude"
                    value={latitude}
                    onChange={(value) => setLatitude(typeof value === 'number' ? value : '')}
                    required
                  />
                  <NumberInput
                    label="Longitude"
                    value={longitude}
                    onChange={(value) => setLongitude(typeof value === 'number' ? value : '')}
                    required
                  />
                  <TextInput label="Name" value={locationName} onChange={(e) => setLocationName(e.target.value)} />
                  <TextInput label="Address" value={locationAddress} onChange={(e) => setLocationAddress(e.target.value)} />
                </Group>
              )}

              {messageType === 'reaction' && (
                <Group grow>
                  <TextInput label="Message ID" value={messageId} onChange={(e) => setMessageId(e.target.value)} required />
                  <TextInput label="Emoji" value={emoji} onChange={(e) => setEmoji(e.target.value)} required />
                </Group>
              )}

              {messageType === 'flow' && (
                <>
                  <Group grow>
                    <TextInput label="Flow ID" value={flowId} onChange={(e) => setFlowId(e.target.value)} required />
                    <TextInput label="Flow Token" value={flowToken} onChange={(e) => setFlowToken(e.target.value)} />
                    <TextInput label="Screen Name" value={flowScreenName} onChange={(e) => setFlowScreenName(e.target.value)} />
                  </Group>
                  <TextInput label="Header" value={flowHeader} onChange={(e) => setFlowHeader(e.target.value)} />
                  <TextInput label="Body" value={flowBody} onChange={(e) => setFlowBody(e.target.value)} required />
                  <TextInput label="Footer" value={flowFooter} onChange={(e) => setFlowFooter(e.target.value)} />
                  <Textarea
                    label="Flow Data JSON"
                    value={rawJSON}
                    onChange={(e) => setRawJSON(e.target.value)}
                    minRows={4}
                    placeholder='{"key":"value"}'
                  />
                </>
              )}

              {(messageType === 'catalog' || messageType === 'product' || messageType === 'product-list') && (
                <>
                  {messageType !== 'catalog' && (
                    <TextInput label="Catalog ID" value={catalogId} onChange={(e) => setCatalogId(e.target.value)} required />
                  )}
                  {messageType === 'product-list' && (
                    <TextInput label="Header Text" value={headerText} onChange={(e) => setHeaderText(e.target.value)} required />
                  )}
                  <TextInput label="Body Text" value={bodyText} onChange={(e) => setBodyText(e.target.value)} required />
                  {messageType === 'product' && (
                    <>
                      <TextInput label="Product Retailer ID" value={productRetailerId} onChange={(e) => setProductRetailerId(e.target.value)} required />
                      <TextInput label="Footer Text" value={footerText} onChange={(e) => setFooterText(e.target.value)} />
                    </>
                  )}
                  {messageType === 'catalog' && (
                    <TextInput
                      label="Thumbnail Product Retailer ID"
                      value={thumbnailProductRetailerId}
                      onChange={(e) => setThumbnailProductRetailerId(e.target.value)}
                    />
                  )}
                  {messageType === 'product-list' && (
                    <Textarea
                      label="Sections JSON"
                      value={rawJSON}
                      onChange={(e) => setRawJSON(e.target.value)}
                      minRows={5}
                      placeholder='[{"title":"Section 1","product_items":[{"product_retailer_id":"sku-1"}]}]'
                      required
                    />
                  )}
                </>
              )}

              {(messageType === 'contacts' || messageType === 'interactive' || messageType === 'template') && (
                <Textarea
                  label={`${messageType} JSON`}
                  value={rawJSON}
                  onChange={(e) => setRawJSON(e.target.value)}
                  minRows={6}
                  required
                />
              )}

              <Group justify="flex-end">
                <Button leftSection={<IconSend size={16} />} type="submit" loading={submitting}>
                  Send
                </Button>
              </Group>
            </Stack>
          </form>
        </Paper>

        {lastApiResponseType && (
          <Paper withBorder p="md">
            <Stack gap="xs">
              <Text fw={600}>
                API Response ({lastApiResponseType === 'success' ? 'Success' : 'Error'})
              </Text>
              <Code
                component="pre"
                block
                color={lastApiResponseType === 'error' ? 'red' : undefined}
                style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}
              >
                {lastApiResponse}
              </Code>
            </Stack>
          </Paper>
        )}
      </Stack>
    </Container>
  );
}
