/* Componentes de apresentação compartilhados pela caixa de entrada do CRM. */

function crmInboxDate(value, includeDate = false) {
  if (!value) return '';
  const date = new Date(String(value).replace(' ', 'T'));
  if (Number.isNaN(date.getTime())) return String(value);
  const today = new Date();
  const sameDay = date.toDateString() === today.toDateString();
  if (!includeDate && sameDay) {
    return date.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' });
  }
  return date.toLocaleString('pt-BR', includeDate
    ? { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }
    : { day: '2-digit', month: '2-digit' });
}

function crmInboxAppointmentDate(value) {
  if (!value) return '';
  const date = new Date(`${value}T12:00:00`);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleDateString('pt-BR', {
    weekday: 'short',
    day: '2-digit',
    month: 'short',
  });
}

function crmInboxPhone(value) {
  const digits = String(value || '').replace(/\D/g, '');
  if (digits.length === 13 && digits.startsWith('55')) {
    return `+55 (${digits.slice(2, 4)}) ${digits.slice(4, 9)}-${digits.slice(9)}`;
  }
  if (digits.length === 12 && digits.startsWith('55')) {
    return `+55 (${digits.slice(2, 4)}) ${digits.slice(4, 8)}-${digits.slice(8)}`;
  }
  return digits ? `+${digits}` : '';
}

function crmInboxContactName(conversation) {
  if (!conversation) return 'Contato';
  const name = String(conversation.displayName || '').trim();
  const nameDigits = name.replace(/\D/g, '');
  const phoneDigits = String(conversation.counterpartPhone || '').replace(/\D/g, '');
  return name && nameDigits !== phoneDigits ? name : crmInboxPhone(phoneDigits);
}

function crmInboxPhoneInput(value) {
  const digits = String(value || '').replace(/\D/g, '').slice(0, 13);
  if (!digits) return '';
  if (digits.startsWith('55')) return crmInboxPhone(digits);
  if (digits.length <= 11) {
    const area = digits.slice(0, 2);
    const number = digits.slice(2);
    const split = number.length > 8 ? 5 : 4;
    return `${area ? `(${area}${area.length === 2 ? ') ' : ''}` : ''}${number.slice(0, split)}${number.length > split ? `-${number.slice(split)}` : ''}`;
  }
  return `+${digits}`;
}

function crmInboxInitials(value) {
  const parts = String(value || '').trim().split(/\s+/).filter(Boolean);
  if (!parts.length) return 'C';
  return `${parts[0][0] || ''}${parts.length > 1 ? parts[parts.length - 1][0] : ''}`.toUpperCase();
}

const crmInboxMessageLabels = {
  pending: 'Pendente',
  sent: 'Enviada',
  delivered: 'Entregue',
  read: 'Lida',
  failed: 'Falhou',
  received: 'Recebida',
};

const crmInboxStatusLabels = {
  open: 'Em atendimento',
  pending: 'Pendente',
  resolved: 'Resolvida',
};

const crmInboxRoleLabels = {
  admin: 'Administrador',
  manager: 'Gerente',
  agent: 'Atendente',
};

function crmInboxMessagePreview(value) {
  const raw = String(value || '');
  if (/^\[Mensagem (unsupported|não compatível)\]$/i.test(raw)) return 'Mensagem não compatível';
  const attributed = raw.match(/^\*([^*\r\n]{1,80}):\*\r?\n?([\s\S]*)$/);
  if (!attributed) return raw;
  return attributed[2].trim() ? `${attributed[1]}: ${attributed[2].trim()}` : attributed[1];
}

function crmInboxReplyPreview(message) {
  if (!message) return 'Mensagem original não carregada';
  const type = String(message.messageType || 'text');
  const labels = {
    image: 'Imagem',
    video: 'Vídeo',
    audio: 'Áudio',
    document: message.mediaFilename || 'Documento',
    sticker: 'Figurinha',
    location: 'Localização',
    contacts: 'Contato',
    unsupported: 'Mensagem não compatível',
  };
  if (labels[type]) return labels[type];
  const preview = crmInboxMessagePreview(message.body).trim();
  return preview || 'Mensagem';
}

function CrmConversationItem({ conversation, active, onClick }) {
  const client = conversation.client || {};
  const contactName = crmInboxContactName(conversation);
  const hasAttributedPreview = /^\*([^*\r\n]{1,80}):\*/.test(String(conversation.lastMessagePreview || ''));
  const messagePreview = crmInboxMessagePreview(conversation.lastMessagePreview);
  return (
    <button
      type="button"
      className={`crm-inbox-conversation${active ? ' active' : ''}${conversation.unreadCount ? ' unread' : ''}`}
      onClick={onClick}
      aria-current={active ? 'true' : undefined}
    >
      <window.Avatar
        initials={crmInboxInitials(contactName)}
        src={client.photoUrl || ''}
        alt={contactName}
        color="gray"
        size={40}
      />
      <span className="crm-inbox-conversation-copy">
        <span className="crm-inbox-conversation-line">
          <strong>{contactName}</strong>
          <time>{crmInboxDate(conversation.lastMessageAt)}</time>
        </span>
        <span className="crm-inbox-conversation-preview">
          {conversation.lastMessageDirection === 'outbound' && !hasAttributedPreview && <span aria-hidden="true">Você: </span>}
          {messagePreview || 'Conversa iniciada'}
        </span>
        <span className="crm-inbox-conversation-meta">
          <span className={`crm-inbox-status crm-inbox-status-${conversation.lastMessageDirection === 'inbound' ? 'awaiting' : conversation.status}`}>
            {conversation.lastMessageDirection === 'inbound' ? 'Aguardando resposta' : (crmInboxStatusLabels[conversation.status] || conversation.status)}
          </span>
          {conversation.assignedUser && <span>{conversation.assignedUser.name}</span>}
        </span>
      </span>
      {conversation.unreadCount > 0 && (
        <span className="crm-inbox-unread" aria-label={`${conversation.unreadCount} mensagens não lidas`}>
          {conversation.unreadCount > 99 ? '99+' : conversation.unreadCount}
        </span>
      )}
    </button>
  );
}

function CrmKanbanCard({ conversation, busy, onOpen, onMove, onDragStart, onDragEnd }) {
  const client = conversation.client || {};
  const contactName = crmInboxContactName(conversation);
  const preview = crmInboxMessagePreview(conversation.lastMessagePreview) || 'Conversa iniciada';
  return (
    <article
      className={`crm-kanban-card${conversation.unreadCount ? ' unread' : ''}${busy ? ' busy' : ''}`}
      draggable={!busy}
      onDragStart={(event) => onDragStart(event, conversation)}
      onDragEnd={onDragEnd}
    >
      <button type="button" className="crm-kanban-card-main" onClick={() => onOpen(conversation.id)}>
        <window.Avatar
          initials={crmInboxInitials(contactName)}
          src={client.photoUrl || ''}
          alt={contactName}
          color="gray"
          size={38}
        />
        <span className="crm-kanban-card-copy">
          <span className="crm-kanban-card-line">
            <strong>{contactName}</strong>
            <time>{crmInboxDate(conversation.lastMessageAt)}</time>
          </span>
          <span className="crm-kanban-card-phone">{crmInboxPhone(conversation.counterpartPhone)}</span>
          <span className="crm-kanban-card-preview">{preview}</span>
        </span>
      </button>
      <footer className="crm-kanban-card-foot">
        <span className="crm-kanban-card-owner">
          <window.Icon name="user" size={12} />
          {conversation.assignedUser ? conversation.assignedUser.name : 'Sem responsável'}
        </span>
        {conversation.unreadCount > 0 && <span className="crm-kanban-card-unread">{conversation.unreadCount} nova{conversation.unreadCount > 1 ? 's' : ''}</span>}
        <select
          value={conversation.lastMessageDirection === 'inbound' ? 'awaiting' : conversation.status}
          aria-label={`Alterar situação de ${contactName}`}
          disabled={busy}
          onChange={(event) => onMove(conversation.id, event.target.value)}
        >
          <option value="awaiting" disabled>Aguardando resposta</option>
          <option value="open">Em atendimento</option>
          <option value="pending">Pendente</option>
          <option value="resolved">Concluída</option>
        </select>
      </footer>
    </article>
  );
}

function crmInboxArrangeMessages(messages) {
  const regular = [];
  const byProviderId = new Map();
  const reactions = [];
  (messages || []).forEach((message) => {
    if (message.messageType === 'reaction') {
      reactions.push(message);
      return;
    }
    const item = { message, reactions: [] };
    regular.push(item);
    if (message.providerMessageId) byProviderId.set(message.providerMessageId, item);
  });
  const unlinked = [];
  reactions.forEach((reaction) => {
    const content = reaction.content || {};
    const target = content.messageId ? byProviderId.get(content.messageId) : null;
    if (!target) {
      unlinked.push({ message: reaction, reactions: [] });
      return;
    }
    const direction = reaction.direction || 'inbound';
    target.reactions = target.reactions.filter((item) => item.direction !== direction);
    if (content.emoji) target.reactions.push({ id: reaction.id, emoji: content.emoji, direction });
  });
  return regular.concat(unlinked).sort((a, b) => Number(a.message.id) - Number(b.message.id));
}

function CrmMessageBubble({ message, reactions = [], replyToMessage = null, contactName = 'Cliente', onReply }) {
  const outbound = message.direction === 'outbound';
  const type = String(message.messageType || 'text');
  const mediaUrl = String(message.mediaUrl || '');
  const [mediaFailed, setMediaFailed] = React.useState(false);
  const [imageViewerOpen, setImageViewerOpen] = React.useState(false);
  React.useEffect(() => setMediaFailed(false), [mediaUrl]);
  const visibleMediaUrl = mediaFailed ? '' : mediaUrl;
  const mediaUnavailable = !visibleMediaUrl && ['image', 'video', 'audio', 'document', 'sticker'].includes(type);
  const content = message.content || {};
  const rawBody = String(message.body || '');
  const attributedBody = outbound ? rawBody.match(/^\*([^*\r\n]{1,80}):\*\r?\n?([\s\S]*)$/) : null;
  const attributedSender = attributedBody ? attributedBody[1].trim() : '';
  const visibleBody = attributedBody ? attributedBody[2] : rawBody;
  const textParts = visibleBody.split(/(https?:\/\/[^\s<]+)/gi);
  const bodyIsFallback = /^\[(Imagem|Vídeo|Áudio|Documento|Figurinha|Localização|Contato|Reação|Mensagem enviada pelo canal oficial)\]$/i.test(visibleBody);
  const isLegacyOfficialPlaceholder = /^\[Mensagem enviada pelo canal oficial\]$/i.test(rawBody);
  const isUnsupported = type === 'unsupported' || /^\[Mensagem (unsupported|não compatível)\]$/i.test(rawBody);
  const replyToProviderMessageId = String(content.replyToMessageId || '');
  const replyAuthor = replyToMessage
    ? (replyToMessage.direction === 'outbound'
      ? ((String(replyToMessage.body || '').match(/^\*([^*\r\n]{1,80}):\*/) || [])[1] || 'Equipe')
      : contactName)
    : 'Mensagem original';
  if (isLegacyOfficialPlaceholder && !mediaUrl) {
    return (
      <div className="crm-inbox-system-message">
        <window.Icon name="phone" size={14} />
        <span>Mensagem enviada pelo celular</span>
        <time>{crmInboxDate(message.providerTimestamp || message.createdAt, true)}</time>
      </div>
    );
  }
  if (type === 'reaction') {
    return (
      <div className="crm-inbox-system-message crm-inbox-reaction-event">
        <span>{content.emoji || '♡'}</span>
        <span>{content.emoji ? 'Reação a uma mensagem anterior' : 'Reação não identificada'}</span>
        <time>{crmInboxDate(message.providerTimestamp || message.createdAt, true)}</time>
      </div>
    );
  }
  if (isUnsupported) {
    return (
      <div className="crm-inbox-unsupported-message" role="status" title={content.details || content.title || ''}>
        <span className="crm-inbox-unsupported-icon"><window.Icon name="info" size={17} /></span>
        <span>
          <strong>Mensagem não compatível</strong>
          <small>Este formato não foi disponibilizado pela Meta. Veja a mensagem pelo WhatsApp.</small>
        </span>
        <time>{crmInboxDate(message.providerTimestamp || message.createdAt, true)}</time>
      </div>
    );
  }
  return (
    <article className={`crm-inbox-message ${outbound ? 'outbound' : 'inbound'}${mediaUnavailable ? ' media-unavailable' : ''}${reactions.length ? ' has-reactions' : ''}`}>
      {typeof onReply === 'function' && message.providerMessageId && (
        <button
          type="button"
          className="crm-message-reply-action"
          onClick={() => onReply(message)}
          title="Responder a esta mensagem"
          aria-label="Responder a esta mensagem"
        >
          <window.Icon name="reply" size={15} />
          <span>Responder</span>
        </button>
      )}
      {replyToProviderMessageId && (
        <div className="crm-message-quoted" title="Mensagem respondida">
          <strong>{replyAuthor}</strong>
          <span>{crmInboxReplyPreview(replyToMessage)}</span>
        </div>
      )}
      {visibleMediaUrl && type === 'image' && (
        <button
          type="button"
          className="crm-message-media-image"
          onClick={() => setImageViewerOpen(true)}
          aria-label="Ampliar imagem"
        >
          <img src={visibleMediaUrl} alt={visibleBody && !bodyIsFallback ? visibleBody : 'Imagem recebida'} loading="lazy" onError={() => setMediaFailed(true)} />
          <span className="crm-message-image-zoom"><window.Icon name="search" size={15} /> Ampliar</span>
        </button>
      )}
      {visibleMediaUrl && type === 'sticker' && <img className="crm-message-sticker" src={visibleMediaUrl} alt="Figurinha" loading="lazy" onError={() => setMediaFailed(true)} />}
      {visibleMediaUrl && type === 'video' && <video className="crm-message-video" src={visibleMediaUrl} controls preload="metadata" onError={() => setMediaFailed(true)} />}
      {visibleMediaUrl && type === 'audio' && <audio className="crm-message-audio" src={visibleMediaUrl} controls preload="metadata" onError={() => setMediaFailed(true)} />}
      {visibleMediaUrl && type === 'document' && (
        <a className="crm-message-document" href={visibleMediaUrl} target="_blank" rel="noopener noreferrer" download>
          <window.Icon name="file" size={20} />
          <span><strong>{message.mediaFilename || 'Documento'}</strong><small>Abrir ou baixar arquivo</small></span>
        </a>
      )}
      {mediaUnavailable && (
        <div className="crm-message-media-unavailable" role="status">
          <span className="crm-message-media-unavailable-icon"><window.Icon name={type === 'audio' ? 'mic' : 'file'} size={19} /></span>
          <span>
            <strong>{type === 'audio' ? 'Áudio indisponível' : 'Mídia indisponível'}</strong>
            <small>{mediaFailed ? 'O arquivo expirou ou não pôde ser carregado.' : 'O arquivo não foi recebido pelo CRM.'}</small>
          </span>
        </div>
      )}
      {type === 'location' && Number.isFinite(Number(content.latitude)) && Number.isFinite(Number(content.longitude)) && (
        <a className="crm-message-location" href={`https://www.google.com/maps?q=${encodeURIComponent(`${content.latitude},${content.longitude}`)}`} target="_blank" rel="noopener noreferrer">
          <window.Icon name="pin" size={21} />
          <span><strong>{content.name || 'Localização compartilhada'}</strong><small>{content.address || 'Abrir no mapa'}</small></span>
        </a>
      )}
      {type === 'contacts' && Array.isArray(content.contacts) && content.contacts.map((contact, index) => (
        <div className="crm-message-contact" key={`${contact.name}-${index}`}>
          <window.Icon name="user" size={20} />
          <span><strong>{contact.name || 'Contato'}</strong><small>{(contact.phones || []).join(' · ') || 'Sem telefone informado'}</small></span>
        </div>
      ))}
      {(!bodyIsFallback || (!visibleMediaUrl && !mediaUnavailable)) && (
        <div className="crm-inbox-message-body">
          {attributedSender && <strong className="crm-inbox-message-sender">{attributedSender}</strong>}
          {textParts.map((part, index) => /^https?:\/\//i.test(part)
            ? <a href={part} target="_blank" rel="noopener noreferrer" key={`${part}-${index}`}>{part}</a>
            : <React.Fragment key={index}>{part}</React.Fragment>)}
        </div>
      )}
      <div className={`crm-inbox-message-foot${message.status === 'failed' ? ' error' : ''}`}>
        <time>{crmInboxDate(message.providerTimestamp || message.createdAt, true)}</time>
        {outbound && (
          <span>
            {crmInboxMessageLabels[message.status] || message.status}
          </span>
        )}
      </div>
      {reactions.length > 0 && (
        <div className={`crm-message-reactions${outbound ? ' outbound' : ''}`} aria-label="Reações da mensagem">
          {reactions.map((reaction) => <span key={reaction.id}>{reaction.emoji}</span>)}
        </div>
      )}
      {imageViewerOpen && visibleMediaUrl && (
        <window.ProfilePhotoViewer
          src={visibleMediaUrl}
          alt={visibleBody && !bodyIsFallback ? visibleBody : 'Imagem da conversa'}
          onClose={() => setImageViewerOpen(false)}
        />
      )}
    </article>
  );
}

function CrmNewConversationModal({
  open,
  contacts,
  contactsLoading,
  contactQuery,
  setContactQuery,
  phone,
  setPhone,
  templates,
  templatesLoading,
  templateKey,
  setTemplateKey,
  templateParameters,
  setTemplateParameters,
  templateMedia,
  setTemplateMedia,
  error,
  busy,
  onClose,
  onSubmit,
}) {
  if (!open) return null;
  const selectedTemplate = templates.find((item) => `${item.name}|${item.language}` === templateKey) || null;
  const requiredParameters = selectedTemplate ? (selectedTemplate.parameters || []) : [];
  const hasMissingParameters = requiredParameters.some((parameter) => !String(templateParameters[parameter.key] || '').trim());
  const hasMissingMedia = !!(selectedTemplate && selectedTemplate.mediaHeader && !templateMedia);
  const previewBody = selectedTemplate
    ? String(selectedTemplate.body || selectedTemplate.name)
      .replace(/\{\{\s*(\d+)\s*\}\}/g, (match, index) => (
        templateParameters[`body:${Number(index)}`] || match
      ))
      .replace(/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g, (match, name) => (
        templateParameters[`body:${name}`] || match
      ))
    : '';
  return (
    <window.Modal
      title="Nova conversa"
      sub="Escolha um cliente da Agenda ou informe um número com país e DDD."
      onClose={onClose}
      footer={(
        <>
          <window.Button variant="outline" onClick={onClose} disabled={busy}>Cancelar</window.Button>
          <window.Button
            icon="send"
            onClick={onSubmit}
            disabled={busy || templatesLoading || !phone.trim() || !templateKey || hasMissingParameters || hasMissingMedia}
          >
            {busy ? 'Enviando…' : 'Enviar mensagem'}
          </window.Button>
        </>
      )}
    >
      <div className="crm-new-conversation">
        {error && <div className="alert danger" role="alert">{error}</div>}
        <window.Field label="Buscar nos clientes da Agenda">
          <div className="crm-inbox-search">
            <window.Icon name="search" size={16} />
            <window.Input
              value={contactQuery}
              placeholder="Nome, telefone ou e-mail"
              onChange={(event) => setContactQuery(event.target.value)}
              autoFocus
            />
          </div>
        </window.Field>
        <div className="crm-contact-results" aria-live="polite">
          {contactsLoading ? (
            <span className="crm-contact-results-empty">Buscando clientes…</span>
          ) : contacts.length === 0 ? (
            <span className="crm-contact-results-empty">Nenhum cliente encontrado.</span>
          ) : contacts.map((contact) => (
            <button
              type="button"
              className={`crm-contact-result${String(phone).replace(/\D/g, '') === String(contact.phone).replace(/\D/g, '') ? ' active' : ''}`}
              key={contact.id}
              onClick={() => setPhone(crmInboxPhoneInput(contact.phone))}
            >
              <window.Avatar
                initials={crmInboxInitials(contact.name)}
                src={contact.photoUrl || ''}
                alt={contact.name}
                color="gray"
                size={34}
              />
              <span>
                <strong>{contact.name}</strong>
                <small>{contact.phone || 'Sem telefone cadastrado'}</small>
              </span>
            </button>
          ))}
        </div>
        <window.Field label="Número do WhatsApp">
          <window.Input
            value={phone}
            inputMode="tel"
            autoComplete="tel"
            placeholder="Ex.: +55 67 99999-9999"
            maxLength={24}
            onChange={(event) => setPhone(crmInboxPhoneInput(event.target.value))}
          />
        </window.Field>
        <window.Field label="Modelo aprovado da Meta">
          <window.Select
            value={templateKey}
            disabled={templatesLoading}
            onChange={(event) => setTemplateKey(event.target.value)}
          >
            <option value="">
              {templatesLoading
                ? 'Carregando modelos...'
                : (templates.length ? 'Selecione um modelo' : 'Nenhum modelo aprovado encontrado')}
            </option>
            {templates.map((template) => (
              <option
                key={`${template.name}|${template.language}`}
                value={`${template.name}|${template.language}`}
                disabled={template.unsupportedVariables}
              >
                {template.name} - {template.language}
                {template.unsupportedVariables
                  ? ' (parâmetro não compatível)'
                  : (template.mediaHeader ? ' (anexar mídia)' : (template.hasVariables ? ' (preencher campos)' : ''))}
              </option>
            ))}
          </window.Select>
        </window.Field>
        {!templatesLoading && templates.length === 0 && (
          <div className="crm-new-conversation-note warning">
            Crie e aprove um modelo no Gerenciador do WhatsApp da conta conectada. Depois, feche e abra esta janela para atualizar a lista.
          </div>
        )}
        {selectedTemplate && requiredParameters.map((parameter) => (
          <window.Field key={parameter.key} label={parameter.label}>
            <window.Input
              value={templateParameters[parameter.key] || ''}
              placeholder={parameter.example ? `Ex.: ${parameter.example}` : 'Preencha este campo'}
              onChange={(event) => setTemplateParameters((current) => ({
                ...current,
                [parameter.key]: event.target.value,
              }))}
            />
          </window.Field>
        ))}
        {selectedTemplate && selectedTemplate.mediaHeader && (
          <window.Field label={selectedTemplate.mediaHeader.label || 'Arquivo do cabeçalho'}>
            <input
              className="input"
              type="file"
              accept={selectedTemplate.mediaHeader.accept || ''}
              onChange={(event) => setTemplateMedia((event.target.files && event.target.files[0]) || null)}
            />
            <small className="muted">
              A imagem usada na aprovação é apenas uma amostra da Meta. A Cloud API exige uma mídia em cada envio. Máximo de 16 MB.
            </small>
          </window.Field>
        )}
        {templateKey && (() => {
          const selected = selectedTemplate;
          return selected ? (
            <div className="crm-template-preview">
              <span>{previewBody}</span>
              {!!(selected.buttons && selected.buttons.length) && (
                <div className="crm-template-buttons">
                  {selected.buttons.map((button) => (
                    <span key={`${button.index}-${button.text}`}>{button.text}</span>
                  ))}
                </div>
              )}
            </div>
          ) : null;
        })()}
        <div className="crm-new-conversation-note">
          Texto livre é permitido quando o cliente iniciou a conversa nas últimas 24 horas.
          Fora desse período, utilize uma mensagem previamente aprovada.
        </div>
      </div>
    </window.Modal>
  );
}

window.CrmInboxParts = {
  crmInboxDate,
  crmInboxAppointmentDate,
  crmInboxPhone,
  crmInboxContactName,
  crmInboxPhoneInput,
  crmInboxInitials,
  crmInboxStatusLabels,
  crmInboxRoleLabels,
  crmInboxReplyPreview,
  CrmConversationItem,
  CrmKanbanCard,
  crmInboxArrangeMessages,
  CrmMessageBubble,
  CrmNewConversationModal,
};
