import axios from 'axios';
import httpClient from '../config/httpClient';
import toolConfigService from './toolConfig.service';
import logger from '../utils/logger';

interface NextcloudLastMessage {
  text: string;
  author: string;
  timestamp: number;
}

interface NextcloudConversation {
  token: string;
  displayName: string;
  unreadMessages: number;
  lastActivity: number;
  lastMessage: NextcloudLastMessage | null;
  type: number;
  url: string;
}

interface ConversationsResult {
  totalUnread: number;
  conversations: NextcloudConversation[];
}

interface LoginFlowResult {
  loginUrl: string;
  pollToken: string;
  pollEndpoint: string;
}

interface LoginFlowCredentials {
  loginName: string;
  appPassword: string;
}

/**
 * Validates that a URL is safe to use as an outbound service endpoint.
 * Rejects non-http(s) protocols and private/loopback IP ranges to prevent SSRF.
 */
function isValidServiceUrl(raw: string): boolean {
  let parsed: URL;
  try {
    parsed = new URL(raw);
  } catch {
    return false;
  }

  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    return false;
  }

  const hostname = parsed.hostname.toLowerCase();

  // Reject plain loopback / localhost names
  if (hostname === 'localhost' || hostname === '::1') {
    return false;
  }

  // Reject numeric IPv4 private / loopback / link-local ranges
  const ipv4Parts = hostname.split('.');
  if (ipv4Parts.length === 4) {
    const [a, b] = ipv4Parts.map(Number);
    if (
      a === 127 ||                         // 127.0.0.0/8  loopback
      a === 10 ||                          // 10.0.0.0/8   private
      (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 private
      (a === 192 && b === 168) ||          // 192.168.0.0/16 private
      (a === 169 && b === 254)             // 169.254.0.0/16 link-local
    ) {
      return false;
    }
  }

  return true;
}

async function initiateLoginFlow(): Promise<LoginFlowResult> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.post(`${baseUrl}/index.php/login/v2`);
    return {
      loginUrl: response.data.login,
      pollToken: response.data.poll.token,
      pollEndpoint: response.data.poll.endpoint,
    };
  } catch (error) {
    if (axios.isAxiosError(error)) {
      logger.error('Nextcloud Login Flow v2 initiation failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
    }
    logger.error('NextcloudService.initiateLoginFlow failed', { error });
    throw new Error('Failed to initiate Nextcloud login flow');
  }
}

async function pollLoginFlow(pollEndpoint: string, pollToken: string): Promise<LoginFlowCredentials | null> {
  if (!isValidServiceUrl(pollEndpoint)) {
    throw new Error('pollEndpoint is not a valid service URL');
  }
  try {
    const response = await httpClient.post(pollEndpoint, `token=${pollToken}`, {
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    });
    return {
      loginName: response.data.loginName,
      appPassword: response.data.appPassword,
    };
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 404) {
      return null;
    }
    if (axios.isAxiosError(error)) {
      logger.error('Nextcloud Login Flow v2 poll failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
    }
    logger.error('NextcloudService.pollLoginFlow failed', { error });
    throw new Error('Failed to poll Nextcloud login flow');
  }
}

interface NextcloudChatMessage {
  id: number;
  token: string;
  actorType: string;
  actorId: string;
  actorDisplayName: string;
  message: string;
  timestamp: number;
  messageType: string;
  systemMessage: string;
  messageParameters: Record<string, any>;
  reactions: Record<string, any>;
  reactionsSelf: string[];
  parent?: NextcloudChatMessage;
}

async function getAllConversations(loginName: string, appPassword: string): Promise<NextcloudConversation[]> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v4/room?format=json`,
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );

    const rooms: any[] = response.data?.ocs?.data ?? [];
    return rooms
      .filter((r: any) => r.type !== 4)
      .sort((a: any, b: any) => (b.lastActivity ?? 0) - (a.lastActivity ?? 0))
      .map((r: any) => ({
        token: r.token,
        displayName: r.displayName,
        unreadMessages: r.unreadMessages ?? 0,
        lastActivity: r.lastActivity ?? 0,
        lastMessage: r.lastMessage
          ? {
              text: r.lastMessage.message ?? '',
              author: r.lastMessage.actorDisplayName ?? '',
              timestamp: r.lastMessage.timestamp ?? 0,
            }
          : null,
        type: r.type,
        url: `${baseUrl}/call/${r.token}`,
      }));
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud app password is invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('Nextcloud getAllConversations failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getAllConversations failed', { error });
    throw new Error('Failed to fetch Nextcloud conversations');
  }
}

interface GetMessagesOptions {
  lookIntoFuture?: boolean;
  lastKnownMessageId?: number;
  timeout?: number;
}

async function getMessages(token: string, loginName: string, appPassword: string, options?: GetMessagesOptions): Promise<NextcloudChatMessage[]> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  const lookIntoFuture = options?.lookIntoFuture ?? false;
  const ncTimeout = options?.timeout ?? 25;

  const params: Record<string, any> = {
    lookIntoFuture: lookIntoFuture ? 1 : 0,
    limit: lookIntoFuture ? 100 : 50,
    setReadMarker: 0,
  };

  if (lookIntoFuture) {
    params.lastKnownMessageId = options?.lastKnownMessageId ?? 0;
    params.timeout = ncTimeout;
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(token)}`,
      {
        params,
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
        ...(lookIntoFuture && {
          timeout: (ncTimeout + 5) * 1000,
          validateStatus: (s: number) => (s >= 200 && s < 300) || s === 304,
        }),
      },
    );

    if (response.status === 304) {
      return [];
    }

    const messages: any[] = response.data?.ocs?.data ?? [];
    return messages.map((m: any) => ({
      id: m.id,
      token: m.token,
      actorType: m.actorType,
      actorId: m.actorId,
      actorDisplayName: m.actorDisplayName,
      message: m.message,
      timestamp: m.timestamp,
      messageType: m.messageType ?? '',
      systemMessage: m.systemMessage ?? '',
      messageParameters: m.messageParameters ?? {},
      reactions: m.reactions ?? {},
      reactionsSelf: m.reactionsSelf ?? [],
      ...(m.parent ? { parent: {
        id: m.parent.id,
        token: m.parent.token,
        actorType: m.parent.actorType,
        actorId: m.parent.actorId,
        actorDisplayName: m.parent.actorDisplayName,
        message: m.parent.message,
        timestamp: m.parent.timestamp,
        messageType: m.parent.messageType ?? '',
        systemMessage: m.parent.systemMessage ?? '',
        messageParameters: m.parent.messageParameters ?? {},
        reactions: m.parent.reactions ?? {},
        reactionsSelf: m.parent.reactionsSelf ?? [],
      }} : {}),
    }));
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.getMessages failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getMessages failed', { error });
    throw new Error('Failed to fetch messages');
  }
}

async function sendMessage(token: string, message: string, loginName: string, appPassword: string, replyTo?: number): Promise<void> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    await httpClient.post(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(token)}`,
      { message, ...(replyTo !== undefined ? { replyTo } : {}) },
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        },
      },
    );
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.sendMessage failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.sendMessage failed', { error });
    throw new Error('Failed to send message');
  }
}

async function markAsRead(token: string, loginName: string, appPassword: string): Promise<void> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    await httpClient.post(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(token)}/read`,
      { lastReadMessage: null },
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        },
      },
    );
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.markAsRead failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.markAsRead failed', { error });
    throw new Error('Failed to mark conversation as read');
  }
}

async function getConversations(loginName: string, appPassword: string): Promise<ConversationsResult> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v4/room?format=json`,
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );

    const rooms: any[] = response.data?.ocs?.data ?? [];

    const filtered = rooms.filter((r: any) => r.type !== 4);

    const totalUnread = filtered.reduce(
      (sum: number, r: any) => sum + (r.unreadMessages ?? 0),
      0,
    );

    const sorted = [...filtered].sort(
      (a: any, b: any) => (b.lastActivity ?? 0) - (a.lastActivity ?? 0),
    );

    const conversations: NextcloudConversation[] = sorted.slice(0, 3).map((r: any) => ({
      token: r.token,
      displayName: r.displayName,
      unreadMessages: r.unreadMessages ?? 0,
      lastActivity: r.lastActivity ?? 0,
      lastMessage: r.lastMessage
        ? {
            text: r.lastMessage.message ?? '',
            author: r.lastMessage.actorDisplayName ?? '',
            timestamp: r.lastMessage.timestamp ?? 0,
          }
        : null,
      type: r.type,
      url: `${baseUrl}/call/${r.token}`,
    }));

    return { totalUnread, conversations };
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud app password is invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('Nextcloud API request failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getConversations failed', { error });
    throw new Error('Failed to fetch Nextcloud conversations');
  }
}

async function uploadFileToTalk(
  token: string,
  fileBuffer: Buffer,
  filename: string,
  mimetype: string,
  loginName: string,
  appPassword: string,
): Promise<void> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;

  // Add timestamp to avoid filename conflicts
  const ext = filename.includes('.') ? filename.slice(filename.lastIndexOf('.')) : '';
  const base = filename.includes('.') ? filename.slice(0, filename.lastIndexOf('.')) : filename;
  const safeName = `${base}_${Date.now()}${ext}`;
  const remotePath = `/Talk/${safeName}`;

  try {
    // Step 1: Upload via WebDAV
    await httpClient.put(
      `${baseUrl}/remote.php/dav/files/${encodeURIComponent(loginName)}${remotePath}`,
      fileBuffer,
      {
        headers: {
          'Authorization': authHeader,
          'Content-Type': mimetype,
        },
      },
    );

    // Step 2: Share file to room
    await httpClient.post(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/chat/${encodeURIComponent(token)}/share`,
      { path: remotePath, shareType: 10 },
      {
        headers: {
          'Authorization': authHeader,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        },
      },
    );
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.uploadFileToTalk failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.uploadFileToTalk failed', { error });
    throw new Error('Failed to upload file to Nextcloud Talk');
  }
}

async function downloadFile(
  filePath: string,
  loginName: string,
  appPassword: string,
): Promise<any> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;

  try {
    const response = await httpClient.get(
      `${baseUrl}/remote.php/dav/files/${encodeURIComponent(loginName)}/${filePath.replace(/^\//, '')}`,
      {
        headers: { 'Authorization': authHeader },
        responseType: 'stream',
      },
    );
    return response;
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.downloadFile failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.downloadFile failed', { error });
    throw new Error('Failed to download file from Nextcloud');
  }
}

async function getFilePreview(
  fileId: number,
  width: number,
  height: number,
  loginName: string,
  appPassword: string,
): Promise<any> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  const authHeader = `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`;

  try {
    const response = await httpClient.get(
      `${baseUrl}/index.php/core/preview`,
      {
        params: { fileId, x: width, y: height, a: 1 },
        headers: { 'Authorization': authHeader },
        responseType: 'stream',
      },
    );
    return response;
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.getFilePreview failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getFilePreview failed', { error });
    throw new Error('Failed to get file preview from Nextcloud');
  }
}

async function searchUsers(query: string, loginName: string, appPassword: string): Promise<any[]> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/core/autocomplete/get?search=${encodeURIComponent(query)}&limit=20&itemType=&itemId=&shareTypes[]=0&shareTypes[]=1&shareTypes[]=7&format=json`,
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );
    return (response.data?.ocs?.data ?? []).map((u: any) => ({ id: u.id, label: u.label, source: u.source }));
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.searchUsers failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.searchUsers failed', { error });
    throw new Error('Failed to search users');
  }
}

async function createRoom(roomType: number, invite: string, roomName: string | undefined, loginName: string, appPassword: string): Promise<{ token: string }> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.post(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v4/room`,
      { roomType, invite, ...(roomName ? { roomName } : {}) },
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        },
      },
    );
    return { token: response.data?.ocs?.data?.token as string };
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.createRoom failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.createRoom failed', { error });
    throw new Error('Failed to create room');
  }
}

async function addReaction(token: string, messageId: number, reaction: string, loginName: string, appPassword: string): Promise<void> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    await httpClient.post(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/reaction/${encodeURIComponent(token)}/${messageId}`,
      { reaction },
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        },
      },
    );
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.addReaction failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.addReaction failed', { error });
    throw new Error('Failed to add reaction');
  }
}

async function removeReaction(token: string, messageId: number, reaction: string, loginName: string, appPassword: string): Promise<void> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    await httpClient.delete(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/reaction/${encodeURIComponent(token)}/${messageId}`,
      {
        params: { reaction },
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.removeReaction failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.removeReaction failed', { error });
    throw new Error('Failed to remove reaction');
  }
}

async function getReactions(token: string, messageId: number, loginName: string, appPassword: string): Promise<Record<string, any>> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/reaction/${encodeURIComponent(token)}/${messageId}`,
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );
    return response.data?.ocs?.data ?? {};
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.getReactions failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getReactions failed', { error });
    throw new Error('Failed to get reactions');
  }
}

async function getPollDetails(token: string, pollId: number, loginName: string, appPassword: string): Promise<Record<string, any>> {
  const { url: baseUrl } = await toolConfigService.getNextcloudConfig();
  if (!baseUrl || !isValidServiceUrl(baseUrl)) {
    throw new Error('NEXTCLOUD_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get(
      `${baseUrl}/ocs/v2.php/apps/spreed/api/v1/poll/${encodeURIComponent(token)}/${pollId}`,
      {
        headers: {
          'Authorization': `Basic ${Buffer.from(loginName + ':' + appPassword).toString('base64')}`,
          'OCS-APIRequest': 'true',
          'Accept': 'application/json',
        },
      },
    );
    return response.data?.ocs?.data ?? {};
  } catch (error) {
    if (axios.isAxiosError(error) && error.response?.status === 401) {
      const err = new Error('Nextcloud authentication invalid');
      (err as any).code = 'NEXTCLOUD_AUTH_INVALID';
      throw err;
    }
    if (axios.isAxiosError(error)) {
      logger.error('NextcloudService.getPollDetails failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
      throw new Error(`Nextcloud API error: ${error.response?.status ?? 'unknown'}`);
    }
    logger.error('NextcloudService.getPollDetails failed', { error });
    throw new Error('Failed to get poll details');
  }
}

export type { NextcloudChatMessage, GetMessagesOptions };
export default { initiateLoginFlow, pollLoginFlow, getConversations, getAllConversations, getMessages, sendMessage, markAsRead, uploadFileToTalk, downloadFile, getFilePreview, searchUsers, createRoom, addReaction, removeReaction, getReactions, getPollDetails };
