/**
 * Chat view — DChain messenger.
 * Safe-area aware header/input, smooth scroll, proper E2E indicators,
 * responsive send button with press feedback.
 */

import React, { useState, useRef, useEffect, useCallback } from 'react';
import {
  View, Text, FlatList, TextInput, TouchableOpacity, Pressable,
  KeyboardAvoidingView, Platform, ActivityIndicator, Alert,
} from 'react-native';
import { router, useLocalSearchParams } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useStore } from '@/lib/store';
import { useMessages } from '@/hooks/useMessages';
import { encryptMessage } from '@/lib/crypto';
import { sendEnvelope } from '@/lib/api';
import { getWSClient } from '@/lib/ws';
import { appendMessage, loadMessages } from '@/lib/storage';
import { formatTime, randomId } from '@/lib/utils';
import { Avatar } from '@/components/ui/Avatar';
import type { Message } from '@/lib/types';

// ─── Design tokens ────────────────────────────────────────────────────────────
const C = {
  bg:      '#0b1220',
  surface: '#111a2b',
  surface2:'#162035',
  surface3:'#1a2640',
  line:    '#1c2840',
  text:    '#e6edf9',
  muted:   '#98a7c2',
  accent:  '#7db5ff',
  ok:      '#41c98a',
  warn:    '#f0b35a',
  err:     '#ff7a87',
} as const;

// ─── Helpers ──────────────────────────────────────────────────────────────────

function shortAddr(a: string, n = 5): string {
  if (!a) return '—';
  return a.length <= n * 2 + 1 ? a : `${a.slice(0, n)}…${a.slice(-n)}`;
}

/** Group messages by calendar day for day-separator labels. */
function dateBucket(ts: number): string {
  const d = new Date(ts * 1000);
  const now = new Date();
  const yday = new Date(); yday.setDate(now.getDate() - 1);
  const same = (a: Date, b: Date) =>
    a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
  if (same(d, now))   return 'Сегодня';
  if (same(d, yday))  return 'Вчера';
  return d.toLocaleDateString('ru', { day: 'numeric', month: 'long' });
}

// A row in the FlatList: either a message or a date separator we inject.
type Row =
  | { kind: 'msg';    msg: Message }
  | { kind: 'sep';    id: string; label: string };

function buildRows(msgs: Message[]): Row[] {
  const rows: Row[] = [];
  let lastBucket = '';
  for (const m of msgs) {
    const b = dateBucket(m.timestamp);
    if (b !== lastBucket) {
      rows.push({ kind: 'sep', id: `sep_${b}_${m.id}`, label: b });
      lastBucket = b;
    }
    rows.push({ kind: 'msg', msg: m });
  }
  return rows;
}

// ─── Screen ───────────────────────────────────────────────────────────────────

export default function ChatScreen() {
  const { id: contactAddress } = useLocalSearchParams<{ id: string }>();
  const keyFile   = useStore(s => s.keyFile);
  const contacts  = useStore(s => s.contacts);
  const messages  = useStore(s => s.messages);
  const setMsgs   = useStore(s => s.setMessages);
  const appendMsg = useStore(s => s.appendMessage);
  const insets    = useSafeAreaInsets();

  const contact  = contacts.find(c => c.address === contactAddress);
  const chatMsgs = messages[contactAddress ?? ''] ?? [];
  const listRef  = useRef<FlatList>(null);

  const [text,    setText]    = useState('');
  const [sending, setSending] = useState(false);
  const [peerTyping, setPeerTyping] = useState(false);

  // Poll relay inbox for messages from this contact
  useMessages(contact?.x25519Pub ?? '');

  // Subscribe to typing indicators sent to us. Clears after 3 seconds of
  // silence so the "typing…" bubble disappears naturally when the peer
  // stops. sendTyping on our side happens per-keystroke (throttled below).
  useEffect(() => {
    if (!keyFile?.x25519_pub) return;
    const ws = getWSClient();
    let clearTimer: ReturnType<typeof setTimeout> | null = null;

    const off = ws.subscribe('typing:' + keyFile.x25519_pub, (frame) => {
      if (frame.event !== 'typing') return;
      const d = frame.data as { from?: string } | undefined;
      // Only show typing for the contact currently open in this view.
      if (!contact?.x25519Pub || d?.from !== contact.x25519Pub) return;
      setPeerTyping(true);
      if (clearTimer) clearTimeout(clearTimer);
      clearTimer = setTimeout(() => setPeerTyping(false), 3_000);
    });

    return () => {
      off();
      if (clearTimer) clearTimeout(clearTimer);
    };
  }, [keyFile?.x25519_pub, contact?.x25519Pub]);

  // Throttled sendTyping: fire on every keystroke but no more than every 2s.
  const lastSentTyping = useRef(0);
  const handleTextChange = useCallback((t: string) => {
    setText(t);
    if (!contact?.x25519Pub || !t.trim()) return;
    const now = Date.now();
    if (now - lastSentTyping.current < 2_000) return;
    lastSentTyping.current = now;
    getWSClient().sendTyping(contact.x25519Pub);
  }, [contact?.x25519Pub]);

  // Load cached messages on mount
  useEffect(() => {
    if (contactAddress) {
      loadMessages(contactAddress).then(cached => {
        setMsgs(contactAddress, cached as Message[]);
      });
    }
  }, [contactAddress]);

  const displayName = contact?.username
    ? `@${contact.username}`
    : contact?.alias ?? shortAddr(contactAddress ?? '', 6);

  const canSend = !!text.trim() && !sending && !!contact?.x25519Pub;

  const send = useCallback(async () => {
    if (!text.trim() || !keyFile || !contact) return;
    if (!contact.x25519Pub) {
      Alert.alert(
        'Ключ ещё не опубликован',
        'Контакт пока не опубликовал ключ шифрования. Попробуйте позже.',
      );
      return;
    }
    setSending(true);
    try {
      const { nonce, ciphertext } = encryptMessage(
        text.trim(),
        keyFile.x25519_priv,
        contact.x25519Pub,
      );
      await sendEnvelope({
        sender_pub:    keyFile.x25519_pub,
        recipient_pub: contact.x25519Pub,
        nonce,
        ciphertext,
      });
      const msg: Message = {
        id:        randomId(),
        from:      keyFile.x25519_pub,
        text:      text.trim(),
        timestamp: Math.floor(Date.now() / 1000),
        mine:      true,
      };
      appendMsg(contact.address, msg);
      await appendMessage(contact.address, msg);
      setText('');
      setTimeout(() => listRef.current?.scrollToEnd({ animated: true }), 50);
    } catch (e: any) {
      Alert.alert('Ошибка отправки', e.message);
    } finally {
      setSending(false);
    }
  }, [text, keyFile, contact]);

  const rows = buildRows(chatMsgs);

  const renderRow = ({ item }: { item: Row }) => {
    if (item.kind === 'sep') {
      return (
        <View style={{ alignItems: 'center', marginVertical: 12 }}>
          <View style={{
            backgroundColor: C.surface2, borderRadius: 999,
            paddingHorizontal: 12, paddingVertical: 4,
          }}>
            <Text style={{ color: C.muted, fontSize: 11, fontWeight: '500' }}>{item.label}</Text>
          </View>
        </View>
      );
    }
    const m = item.msg;
    return (
      <View style={{
        flexDirection: 'row',
        justifyContent: m.mine ? 'flex-end' : 'flex-start',
        paddingHorizontal: 12,
        marginBottom: 6,
      }}>
        {!m.mine && (
          <View style={{ marginRight: 8, marginBottom: 4, flexShrink: 0 }}>
            <Avatar name={displayName} size="sm" />
          </View>
        )}
        <View style={{
          maxWidth: '78%',
          backgroundColor: m.mine ? C.accent : C.surface,
          borderRadius: 18,
          borderTopRightRadius: m.mine ? 6 : 18,
          borderTopLeftRadius:  m.mine ? 18 : 6,
          paddingHorizontal: 14,
          paddingTop: 9, paddingBottom: 7,
          borderWidth: m.mine ? 0 : 1,
          borderColor: C.line,
        }}>
          <Text style={{
            color: m.mine ? C.bg : C.text,
            fontSize: 15, lineHeight: 21,
          }}>
            {m.text}
          </Text>
          <View style={{
            flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end',
            marginTop: 3, gap: 4,
          }}>
            <Text style={{
              color: m.mine ? 'rgba(11,18,32,0.65)' : C.muted,
              fontSize: 10,
            }}>
              {formatTime(m.timestamp)}
            </Text>
            {m.mine && (
              <Ionicons
                name="checkmark-done"
                size={12}
                color="rgba(11,18,32,0.65)"
              />
            )}
          </View>
        </View>
      </View>
    );
  };

  return (
    <KeyboardAvoidingView
      style={{ flex: 1, backgroundColor: C.bg }}
      behavior={Platform.OS === 'ios' ? 'padding' : undefined}
      keyboardVerticalOffset={0}
    >
      {/* ── Header ── */}
      <View style={{
        flexDirection: 'row', alignItems: 'center',
        paddingHorizontal: 10,
        paddingTop: insets.top + 8,
        paddingBottom: 10,
        borderBottomWidth: 1, borderBottomColor: C.line,
        backgroundColor: C.surface,
      }}>
        <TouchableOpacity
          onPress={() => router.back()}
          activeOpacity={0.6}
          style={{ padding: 8, marginRight: 4 }}
          hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
        >
          <Ionicons name="chevron-back" size={24} color={C.accent} />
        </TouchableOpacity>

        <View style={{ marginRight: 10, position: 'relative' }}>
          <Avatar name={displayName} size="sm" />
          {contact?.x25519Pub && (
            <View style={{
              position: 'absolute', right: -2, bottom: -2,
              width: 12, height: 12, borderRadius: 6,
              backgroundColor: C.ok,
              borderWidth: 2, borderColor: C.surface,
            }} />
          )}
        </View>

        <View style={{ flex: 1, minWidth: 0 }}>
          <Text style={{ color: C.text, fontWeight: '600', fontSize: 15 }} numberOfLines={1}>
            {displayName}
          </Text>
          <View style={{ flexDirection: 'row', alignItems: 'center', gap: 4, marginTop: 1 }}>
            {peerTyping ? (
              <>
                <Ionicons name="ellipsis-horizontal" size={12} color={C.accent} />
                <Text style={{ color: C.accent, fontSize: 11, fontWeight: '500' }}>печатает…</Text>
              </>
            ) : contact?.x25519Pub ? (
              <>
                <Ionicons name="lock-closed" size={10} color={C.ok} />
                <Text style={{ color: C.ok, fontSize: 11, fontWeight: '500' }}>E2E шифрование</Text>
              </>
            ) : (
              <>
                <Ionicons name="time-outline" size={10} color={C.warn} />
                <Text style={{ color: C.warn, fontSize: 11 }}>Ожидание ключа шифрования</Text>
              </>
            )}
          </View>
        </View>

        <TouchableOpacity
          activeOpacity={0.6}
          style={{ padding: 8 }}
          hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
        >
          <Ionicons name="ellipsis-vertical" size={18} color={C.muted} />
        </TouchableOpacity>
      </View>

      {/* ── Messages ── */}
      <FlatList
        ref={listRef}
        data={rows}
        keyExtractor={r => r.kind === 'sep' ? r.id : r.msg.id}
        renderItem={renderRow}
        contentContainerStyle={{ paddingTop: 14, paddingBottom: 10, flexGrow: 1 }}
        onContentSizeChange={() => listRef.current?.scrollToEnd({ animated: false })}
        ListEmptyComponent={() => (
          <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32, gap: 14 }}>
            <View style={{
              width: 76, height: 76, borderRadius: 38,
              backgroundColor: 'rgba(125,181,255,0.08)',
              alignItems: 'center', justifyContent: 'center',
            }}>
              <Ionicons name="lock-closed-outline" size={34} color={C.accent} />
            </View>
            <Text style={{ color: C.text, fontSize: 15, fontWeight: '600', textAlign: 'center' }}>
              Начните разговор
            </Text>
            <Text style={{ color: C.muted, fontSize: 13, textAlign: 'center', lineHeight: 20 }}>
              Сообщения зашифрованы end-to-end.{'\n'}Только вы и {displayName} их прочитаете.
            </Text>
          </View>
        )}
        showsVerticalScrollIndicator={false}
      />

      {/* ── Input bar ── */}
      <View style={{
        flexDirection: 'row', alignItems: 'flex-end', gap: 8,
        paddingHorizontal: 10,
        paddingTop: 8,
        paddingBottom: Math.max(insets.bottom, 8),
        borderTopWidth: 1, borderTopColor: C.line,
        backgroundColor: C.surface,
      }}>
        <View style={{
          flex: 1,
          backgroundColor: C.surface2,
          borderRadius: 22,
          borderWidth: 1, borderColor: C.line,
          paddingHorizontal: 14, paddingVertical: 8,
          minHeight: 42, maxHeight: 140,
          justifyContent: 'center',
        }}>
          <TextInput
            value={text}
            onChangeText={handleTextChange}
            placeholder="Сообщение…"
            placeholderTextColor={C.muted}
            multiline
            maxLength={2000}
            style={{
              color: C.text, fontSize: 15, lineHeight: 21,
              // iOS needs explicit padding:0 to avoid extra vertical space
              paddingTop: 0, paddingBottom: 0,
            }}
          />
        </View>

        <Pressable
          onPress={send}
          disabled={!canSend}
          style={({ pressed }) => ({
            width: 42, height: 42, borderRadius: 21,
            backgroundColor: canSend ? C.accent : C.surface2,
            alignItems: 'center', justifyContent: 'center',
            flexShrink: 0,
            opacity: pressed && canSend ? 0.7 : 1,
            transform: [{ scale: pressed && canSend ? 0.95 : 1 }],
          })}
        >
          {sending
            ? <ActivityIndicator color={C.bg} size="small" />
            : <Ionicons
                name="send"
                size={18}
                color={canSend ? C.bg : C.muted}
                style={{ marginLeft: 2 }}  // visual centre of the paper-plane glyph
              />
          }
        </Pressable>
      </View>
    </KeyboardAvoidingView>
  );
}
