<template>
  <div class="main-container">
    <!-- SIDEBAR -->
    <div class="sidebar">
      <div class="sidebar-header">
        <h2>Chats</h2>
        <div class="user-info">Logged as: <strong>{{ currentUser }}</strong></div>
        <button class="btn btn-small" @click="openNewChatModal">+ New Chat</button>
        <button class="btn btn-small" @click="logout" style="background: #e74c3c;">Logout</button>
      </div>

      <div class="tabs">
        <div class="tab" :class="{ active: currentTab === 'chats' }" @click="currentTab = 'chats'">Chats</div>
        <div class="tab" :class="{ active: currentTab === 'users' }" @click="currentTab = 'users'">Users</div>
      </div>

      <div class="sidebar-content scrollbar">
        <div v-if="currentTab === 'chats'">
          <div v-if="chats.length === 0" class="loading-spinner">No chats yet</div>
          <div v-for="chat in chats" :key="chat.chat_id" class="chat-item" :class="{ selected: selectedChat?.chat_id === chat.chat_id }" @click="selectChat(chat)">
            <div class="chat-item-name">{{ chat.chat_name }}</div>
            <div class="chat-item-info">{{ chat.is_group ? 'Group' : 'Direct' }} • {{ new Date(chat.creation_date).toLocaleDateString() }}</div>
          </div>
        </div>

        <div v-else>
          <div v-if="users.length === 0" class="loading-spinner">No users available</div>
          <div v-for="user in users" :key="user.user_id" class="user-item">
            <div>
              <div class="user-item-name">{{ user.user_displayname || user.user_name }}</div>
              <div class="user-item-info">@{{ user.user_name }}</div>
            </div>
            <button class="user-select-btn" @click="toggleUserSelection(user.user_id)">
              {{ selectedUsers.includes(user.user_id) ? '✓' : 'Add' }}
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- CHAT VIEW -->
    <div class="chat-view">
      <div v-if="!selectedChat" class="empty-state">
        Select a chat to start messaging
      </div>

      <template v-else>
        <div class="chat-header">
          <div>
            <h2>{{ selectedChat.chat_name }}</h2>
            <div class="chat-header-info">{{ selectedChat.is_group ? 'Group Chat' : 'Direct Message' }}</div>
          </div>
        </div>

        <div class="messages-container">
          <div v-for="msg in messages" :key="msg.message_id" class="message-group" :class="{ mine: msg.user_id === 14 }">
              <div>
                  <div class="message-sender">{{ msg.user_id === 14 ? 'You' : 'User' }}</div>
                  <div class="message-content" :class="{ 'message-error': msg.error }">
                      {{ msg.decryptedText }}
                      <span v-if="msg.signatureChecked" class="signature-badge" :class="{ valid: msg.signatureValid, invalid: !msg.signatureValid }">
                          {{ msg.signatureValid ? '✓ Verified' : '✗ Invalid' }}
                      </span>
                  </div>
                  <div class="message-time">{{ formatTime(msg.sent_at) }}</div>
              </div>
          </div>
      </div>


        <div class="composer">
          <input v-model="messageText" type="text" placeholder="Type a message..." @keyup.enter="sendMessage" />
          <button class="btn-send" @click="sendMessage" :disabled="!messageText.trim() || loading">Send</button>
        </div>
      </template>
    </div>

    <!-- NEW CHAT MODAL -->
    <div v-if="showNewChatModal" class="modal-overlay" @click.self="showNewChatModal = false">
      <div class="modal">
        <h3>Start New Chat</h3>
        <p>Select users to chat with:</p>
        <div class="modal-users-list">
          <div v-for="user in users" :key="user.user_id" class="modal-user-item">
            <label>
              <input type="checkbox" :value="user.user_id" v-model="selectedUsers" />
              {{ user.user_displayname || user.user_name }} (@{{ user.user_name }})
            </label>
          </div>
        </div>
        <div class="modal-buttons">
          <button class="btn" @click="showNewChatModal = false" style="background: #999;">Cancel</button>
          <button class="btn" @click="createChat" :disabled="selectedUsers.length === 0 || loading">Create Chat</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue';
import axios from 'axios';
import { CryptoUtil } from '../utils/crypto';

const emit = defineEmits(['currentUser', 'onLogout']);

const apiBase = ref('http://127.0.0.1:8000');
const currentTab = ref('chats');
const selectedChat = ref(null);
const messageText = ref('');
const loading = ref(false);
const showNewChatModal = ref(false);
const selectedUsers = ref([]);
const messages = ref([]);
const chats = ref([]);
const chatsPublicKeys = ref({});
const users = ref([]);
const messageRefreshInterval = ref(null);
const currentUserId = ref(null);
const decryptedMessagesCache = ref({});

const userKeys = reactive({
  rsaEncPrivate: null,
  rsaEncPublic: null,
  rsaSignPrivate: null,
  rsaSignPublic: null,
  aesKey: null
});

onMounted(async () => {
  await initializeUser();
  await loadChats();
  await loadUsers();
  startMessageRefresh();
});

onUnmounted(() => {
  stopMessageRefresh();
});

const initializeUser = async () => {
  try {
    const password = sessionStorage.getItem('password');
    if (!password) {
      console.error('No password in sessionStorage');
      return;
    }

    // Derive the SAME AES key using the SAME password
    const aesKey = await CryptoUtil.deriveAESKey(password);
    userKeys.aesKey = aesKey;

    // Fetch encrypted keys from backend
    const keysResponse = await axios.post(`${apiBase.value}/get_mykeys`, {}, {
      withCredentials: true
    });

    const encStr = keysResponse.data.protected_enc_privatekey;
    const signStr = keysResponse.data.protected_sign_privatekey;
    const encPublicKeyB64 = keysResponse.data.enc_publickey;
    const signPublicKeyB64 = keysResponse.data.sign_publickey;

    if (!encStr || !signStr || !encPublicKeyB64 || !signPublicKeyB64) {
      console.error('Missing keys from backend');
      return;
    }

    // Parse JSON {ciphertext, iv}
    let encPrivateKeyObj, signPrivateKeyObj;
    try {
      encPrivateKeyObj = JSON.parse((encStr.replaceAll("'", '"')));   
      signPrivateKeyObj = JSON.parse((signStr.replaceAll("'", '"'))); 
      // encPrivateKeyObj = JSON.parse(encStr);   // Backend returns JSON string
      // signPrivateKeyObj = JSON.parse(signStr);
    } catch (e) {
      console.error('JSON parse failed:', e);
      return;
    }

    // Decrypt with the derived AES key
    const decEncPrivateRaw = await CryptoUtil.decryptMessage(
      encPrivateKeyObj.ciphertext,
      encPrivateKeyObj.iv,
      aesKey  // <-- MUST be same key as registration
    );
    const decSignPrivateRaw = await CryptoUtil.decryptMessage(
      signPrivateKeyObj.ciphertext,
      signPrivateKeyObj.iv,
      aesKey  // <-- MUST be same key as registration
    );

    // Import and set keys
    userKeys.rsaEncPrivate = await CryptoUtil.importPrivateKey(decEncPrivateRaw, 'RSA-OAEP', 'SHA-256');
    userKeys.rsaSignPrivate = await CryptoUtil.importPrivateKey(decSignPrivateRaw, 'RSA-PSS', 'SHA-512');
    userKeys.rsaEncPublic = await CryptoUtil.importPublicKey(encPublicKeyB64, 'RSA-OAEP', 'SHA-256');
    userKeys.rsaSignPublic = await CryptoUtil.importPublicKey(signPublicKeyB64, 'RSA-PSS', 'SHA-512');

    console.log('✓ Keys initialized successfully');
  } catch (err) {
    console.error('Failed to initialize user keys:', err);
  }
};


const loadChats = async () => {
  try {
    const response = await axios.post(`${apiBase.value}/get_chats`, {}, {
      withCredentials: true
    });
    chats.value = response.data.chats || [];


  } catch (err) {
    console.error('Error loading chats:', err);
  }
};

const LoadChatKeys = async (chat_id) => {
  try {
    const formData = new FormData();
    formData.append('chat_id', chat_id);

    const res = await axios.post(`${apiBase.value}/get_chat_publickeys`, formData, {
      withCredentials: true
    });

    const usersKeys = res.data.users_keys || [];

    // Build a cache per user_id for this chat
    const map = {};
    for (const u of usersKeys) {
      map[u.user_id] = {
        encPublicKeyB64: u.enc_publickey,
        signPublicKeyB64: u.sign_publickey,
        encKey: null,   // will hold imported CryptoKey
        signKey: null
      };
    }
    chatsPublicKeys.value = map;
  } catch (err) {
    console.error('Error loading chat keys:', err);
  }
};

const loadUsers = async () => {
  try {
    const response = await axios.post(`${apiBase.value}/get_users`, {}, {
      withCredentials: true
    });
    users.value = response.data.users || [];
  } catch (err) {
    console.error('Error loading users:', err);
  }
};

const selectChat = async (chat) => {
  selectedChat.value = chat;
  currentTab.value = 'chats';
  await LoadChatKeys(chat.chat_id);
  await loadMessages();
};

const toggleUserSelection = (userId) => {
  if (selectedUsers.value.includes(userId)) {
    selectedUsers.value = selectedUsers.value.filter(u => u !== userId);
  } else {
    selectedUsers.value.push(userId);
  }
};

const openNewChatModal = () => {
  selectedUsers.value = [];
  showNewChatModal.value = true;
};

const createChat = async () => {
  if (selectedUsers.value.length === 0) return;

  loading.value = true;

  try {
    const targetUserIds = selectedUsers.value.join(',');
    await axios.post(`${apiBase.value}/init_chat`, new URLSearchParams({
      target_userID: targetUserIds,
      withCredentials: true
    }), {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      withCredentials: true
    });

    showNewChatModal.value = false;
    await loadChats();
  } catch (err) {
    console.error('Failed to create chat:', err);
  } finally {
    loading.value = false;
  }
};

const loadMessages = async () => {
  if (!selectedChat.value) return;

  try {
    const response = await axios.post(`${apiBase.value}/get_messages`, new URLSearchParams({
      chat_id: selectedChat.value.chat_id,
      withCredentials: true
    }), {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      withCredentials: true
    });

    const msgsData = response.data.messages || [];

    messages.value = await Promise.all(msgsData.map(async (msg) => {
      const cacheKey = `${msg.message_id}`;
      
      // Check if already decrypted in this session
      if (decryptedMessagesCache.value[cacheKey]) {
        return decryptedMessagesCache.value[cacheKey];
      }

      try {
        // 1. Parse enc_content to get ciphertext and IV
        let encContentObj;
        try {
          encContentObj = JSON.parse(((msg.enc_content).replaceAll("'", '"')));
        } catch (e) {
          console.error(`Failed to parse enc_content for message ${msg.message_id}:`, e);
          throw new Error('Invalid message format');
        }

        const ciphertext = encContentObj.ciphertext;
        const iv = encContentObj.iv;

        if (!ciphertext || !iv) {
          throw new Error('Missing ciphertext or IV in enc_content');
        }

        // 2. Decrypt AES key
        const aesKey = await CryptoUtil.decryptAESKey(
          msg.encrypted_symetrickey,
          userKeys.rsaEncPrivate
        );

        // 3. Decrypt message content
        const decryptedText = await CryptoUtil.decryptMessage(
          ciphertext,
          iv,
          aesKey
        );

        // 4. Verify signature
        let signatureValid = false;
        if (msg.signature && msg.sign_publickey) {
          // Hash the decrypted message
          const messageHash = await CryptoUtil.hashMessage(decryptedText);
          
          // Verify the signature
          signatureValid = await CryptoUtil.verifySignature(
            messageHash,
            msg.signature,
            msg.sign_publickey
          );
        }

        const processedMsg = {
          ...msg,
          decryptedText,
          error: false,
          signatureValid: signatureValid,
          signatureChecked: true
        };

        // Cache it
        decryptedMessagesCache.value[cacheKey] = processedMsg;
        return processedMsg;

      } catch (e) {
        console.error(`Failed to decrypt message ${msg.message_id}:`, e);
        
        const errorMsg = {
          ...msg,
          decryptedText: '[Failed to decrypt]',
          error: true,
          signatureValid: false,
          signatureChecked: false
        };

        // Cache the error too so we don't retry
        decryptedMessagesCache.value[cacheKey] = errorMsg;
        return errorMsg;
      }
    }));

    messages.value.sort((a, b) => b.message_id - a.message_id);

  } catch (err) {
    console.error('Error loading messages:', err);
  }
};



const sendMessage = async () => {
  console.log('sendMessage called', {
    text: messageText.value,
    hasChat: !!selectedChat.value,
    hasSignKey: !!userKeys.rsaSignPrivate
  });

  if (!messageText.value.trim() || !selectedChat.value || !userKeys.rsaSignPrivate) return;

  loading.value = true;

  try {
    // 1. Generate AES key for this message
    const messageAesKey = await crypto.subtle.generateKey(
      { name: 'AES-GCM', length: 256 },
      true,
      ['encrypt', 'decrypt']
    );

    // 2. Encrypt message once with AES
    const ciphertext= JSON.stringify(await CryptoUtil.encryptMessage(messageText.value, messageAesKey));


    // 3. Sign the message hash
    const messageHash = await CryptoUtil.hashMessage(messageText.value);
    const signature = await CryptoUtil.signMessage(messageHash, userKeys.rsaSignPrivate);

    // 4. Export raw AES key (to re-use per recipient)
    const rawAesKey = await crypto.subtle.exportKey('raw', messageAesKey);

    // 5. Build recipients list with encrypted keys
    const recipients = [];
    for (const [userIdStr, keyInfo] of Object.entries(chatsPublicKeys.value)) {
      const userId = parseInt(userIdStr, 10);

      // Import (or reuse cached) RSA-OAEP public key
      if (!keyInfo.encKey) {
        keyInfo.encKey = await CryptoUtil.importPublicKey(
          keyInfo.encPublicKeyB64,
          'RSA-OAEP',
          'SHA-256'
        );
      }

      const encryptedAesKeyB64 = CryptoUtil.bufToBase64(
        await crypto.subtle.encrypt(
          { name: 'RSA-OAEP' },
          keyInfo.encKey,
          rawAesKey
        )
      );

      recipients.push({
        user_id: userId,
        encrypted_key: encryptedAesKeyB64
      });
    }

    // 6. Build ONE form data with all recipients
    const formData = new FormData();
    formData.append('chat_id', selectedChat.value.chat_id);
    formData.append('enc_message', ciphertext);
    console.log(ciphertext)
    formData.append('signature', signature);
    formData.append('recipients', JSON.stringify(recipients));  // Send as JSON array

    // 7. Single POST call
    await axios.post(`${apiBase.value}/send_message`, formData, {
      withCredentials: true
    });

    messageText.value = '';
    await loadMessages();
  } catch (err) {
    console.error('Error sending message:', err);
  } finally {
    loading.value = false;
  }
};


const startMessageRefresh = () => {
  messageRefreshInterval.value = setInterval(() => {
    if (selectedChat.value) {
      loadMessages();
    }
  }, 2000);
};

const stopMessageRefresh = () => {
  if (messageRefreshInterval.value) {
    clearInterval(messageRefreshInterval.value);
  }
};

const formatTime = (dateString) => {
  const date = new Date(dateString);
  return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
};

const logout = () => {
  emit('logout');
};
</script>

<style scoped>



.main-container {
  display: flex;
  width: 100%;
  height: 100vh;
}

.sidebar {
  width: 350px;
  background: white;
  border-right: 1px solid #e0e0e0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.sidebar-header {
  padding: 20px;
  border-bottom: 1px solid #e0e0e0;
  background: #f9f9f9;
}

.sidebar-header h2 {
  font-size: 18px;
  margin-bottom: 10px;
}

.sidebar-header .user-info {
  font-size: 12px;
  color: #666;
  margin-bottom: 15px;
}

.sidebar-header .btn-small {
  padding: 8px 16px;
  font-size: 13px;
  margin-right: 5px;
  margin-bottom: 5px;
}

.tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid #e0e0e0;
}

.tab {
  flex: 1;
  padding: 12px;
  text-align: center;
  cursor: pointer;
  border-bottom: 3px solid transparent;
  background: #f9f9f9;
  font-size: 13px;
  font-weight: 600;
  color: #666;
  transition: all 0.3s;
}

.tab.active {
  color: #667eea;
  border-bottom-color: #667eea;
  background: white;
}

.sidebar-content {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  scrollbar-width: thin;
  scrollbar-color: #ccc #f1f1f1;
}

.chat-item, .user-item {
  padding: 12px;
  margin-bottom: 8px;
  background: #f9f9f9;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s;
  border-left: 3px solid transparent;
}

.chat-item:hover, .user-item:hover {
  background: #f0f0f0;
}

.chat-item.selected {
  background: #e8eaf6;
  border-left-color: #667eea;
}

.chat-item-name, .user-item-name {
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 4px;
}

.chat-item-info, .user-item-info {
  font-size: 12px;
  color: #999;
}

.user-select-btn {
  padding: 6px 12px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 11px;
  cursor: pointer;
  margin-top: 8px;
  width: 100%;
}

.user-select-btn:hover {
  background: #5568d3;
}

.loading-spinner {
  text-align: center;
  padding: 20px;
  color: #999;
  font-size: 13px;
}

.chat-view {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: white;
}

.chat-header {
  padding: 20px;
  background: #f9f9f9;
  border-bottom: 1px solid #e0e0e0;
}

.chat-header h2 {
  font-size: 18px;
  color: #333;
}

.chat-header-info {
  font-size: 12px;
  color: #999;
  margin-top: 4px;
}

.messages-container {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
}

.message-group {
  display: flex;
  margin-bottom: 10px;
  animation: slideIn 0.3s ease;
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.message-group.mine {
  justify-content: flex-end;
}

.message-content {
  max-width: 60%;
  padding: 12px 16px;
  border-radius: 12px;
  background: #f0f0f0;
  word-wrap: break-word;
  font-size: 14px;
}

.message-group.mine .message-content {
  background: #667eea;
  color: white;
}

.message-sender {
  font-size: 12px;
  color: #999;
  margin-bottom: 4px;
  padding: 0 16px;
}

.message-time {
  font-size: 11px;
  color: #ccc;
  margin-top: 4px;
  padding: 0 16px;
}

.message-error {
  background: #ffe0e0 !important;
  color: #e74c3c !important;
}

.composer {
  padding: 20px;
  background: #f9f9f9;
  border-top: 1px solid #e0e0e0;
  display: flex;
  gap: 10px;
}

.composer input {
  flex: 1;
  padding: 12px 16px;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  font-size: 14px;
}

.composer input:focus {
  outline: none;
  border-color: #667eea;
  box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
}

.composer .btn-send {
  padding: 12px 24px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.3s;
}

.composer .btn-send:hover {
  background: #5568d3;
}

.composer .btn-send:disabled {
  background: #ccc;
  cursor: not-allowed;
}

.empty-state {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #999;
  font-size: 16px;
}

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal {
  background: white;
  padding: 30px;
  border-radius: 12px;
  max-width: 500px;
  width: 90%;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}

.modal h3 {
  margin-bottom: 20px;
  font-size: 18px;
}

.modal-users-list {
  margin-bottom: 20px;
  max-height: 300px;
  overflow-y: auto;
}

.modal-user-item {
  padding: 10px;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-buttons {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.modal-buttons .btn {
  width: auto;
  padding: 10px 20px;
}

.btn {
  padding: 12px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.3s;
}

.btn:hover {
  background: #5568d3;
}

.btn:disabled {
  background: #ccc;
  cursor: not-allowed;
}

.signature-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
}

.signature-badge.valid {
    background: #d4edda;
    color: #155724;
}

.signature-badge.invalid {
    background: #f8d7da;
    color: #721c24;
}

.message-group.mine .signature-badge.valid {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
}

.message-group.mine .signature-badge.invalid {
    background: rgba(255, 100, 100, 0.3);
    color: #fff;
}


</style>
