/**
 * GraphQL клиент для работы с Doma AI API
 * Документация: https://developers.doma.ai/ru/docs/api/about
 */

import { settingsService, DomaAISettings } from './settingsService';
import { getAuthToken } from './apiClient';

export interface DomaGraphQLResponse<T> {
  data?: T;
  errors?: Array<{
    message: string;
    extensions?: any;
  }>;
}

export interface DomaAuthResponse {
  authenticateUserWithPassword: {
    token: string;
    item: {
      id: string;
      name: string;
      email?: string;
      phone?: string;
    };
  };
}

export interface DomaTicket {
  id: string;
  number: string;
  status: {
    id: string;
    name: string;
    type: string;
  };
  details?: string;
  description?: string;
  createdAt: string;
  updatedAt: string;
  deadline?: string;
  property?: {
    id: string;
    address: string;
    unitName?: string;
  };
  client?: {
    id: string;
    name: string;
    phone?: string;
  };
  assignee?: {
    id: string;
    name: string;
  };
  category?: {
    id: string;
    name: string;
  };
}

export interface DomaTicketsResponse {
  objs: DomaTicket[];
  meta?: {
    count: number;
  };
}

class DomaGraphQLClient {
  private apiUrl: string | null = null;
  private token: string | null = null;
  private tokenStorageKey = 'doma_ai_token';

  constructor() {
    // Восстанавливаем токен из localStorage, если есть
    const storedToken = localStorage.getItem(this.tokenStorageKey);
    if (storedToken) {
      this.token = storedToken;
    }
    
    // Настраиваем URL бэкенда, через который проксируем запросы в Doma AI
    this.updateApiUrl();
  }

  /**
   * Обновляет URL API до нашего backend-прокси, а не напрямую до Doma AI
   */
  private updateApiUrl(): void {
    const backendBaseUrl = import.meta.env.VITE_API_BASE_URL;

    if (backendBaseUrl) {
      // Все запросы к Doma AI теперь идут через backend-прокси
      this.apiUrl = `${backendBaseUrl.replace(/\/$/, '')}/doma/graphql`;
      return;
    }

    this.apiUrl = null;
    console.warn(
      '[DomaGraphQLClient] VITE_API_BASE_URL не задан. ' +
      'Настройте URL бэкенда в переменных окружения фронтенда.'
    );
  }

  /**
   * Устанавливает настройки API из настроек интеграций
   */
  updateSettings(): void {
    this.updateApiUrl();
  }

  /**
   * Аутентификация пользователя через email и пароль
   * Если параметры не переданы, пытается получить из настроек
   */
  async authenticate(email?: string, password?: string): Promise<string> {
    // Если параметры не переданы, пытаемся получить из настроек
    if (!email || !password) {
      const settings = settingsService.getDomaAISettings();
      if (settings?.email && settings?.password) {
        email = settings.email;
        password = settings.password;
      } else {
        throw new Error('Учетные данные не указаны. Укажите email и пароль в настройках интеграций.');
      }
    }
    
    // Обновляем URL перед авторизацией
    this.updateApiUrl();
    const mutation = `
      mutation AuthenticateUser($email: String!, $password: String!) {
        authenticateUserWithPassword(email: $email, password: $password) {
          token
          item {
            id
            name
            email
            phone
          }
        }
      }
    `;

    const response = await this.request<DomaAuthResponse>(mutation, {
      email,
      password,
    });

    if (response.errors) {
      throw new Error(response.errors[0]?.message || 'Ошибка аутентификации');
    }

    if (response.data?.authenticateUserWithPassword?.token) {
      this.token = response.data.authenticateUserWithPassword.token;
      localStorage.setItem(this.tokenStorageKey, this.token);
      return this.token;
    }

    throw new Error('Не удалось получить токен авторизации');
  }

  /**
   * Аутентификация через телефон и пароль
   * Если параметры не переданы, пытается получить из настроек
   */
  async authenticateWithPhone(phone?: string, password?: string): Promise<string> {
    // Если параметры не переданы, пытаемся получить из настроек
    if (!phone || !password) {
      const settings = settingsService.getDomaAISettings();
      if (settings?.phone && settings?.password) {
        phone = settings.phone;
        password = settings.password;
      } else {
        throw new Error('Учетные данные не указаны. Укажите телефон и пароль в настройках интеграций.');
      }
    }
    
    // Обновляем URL перед авторизацией
    this.updateApiUrl();
    const mutation = `
      mutation AuthenticateUserWithPhone($phone: String!, $password: String!) {
        authenticateUserWithPhoneAndPassword(phone: $phone, password: $password) {
          token
          item {
            id
            name
            email
            phone
          }
        }
      }
    `;

    interface PhoneAuthResponse {
      authenticateUserWithPhoneAndPassword: {
        token: string;
        item: {
          id: string;
          name: string;
          email?: string;
          phone?: string;
        };
      };
    }

    const response = await this.request<PhoneAuthResponse>(mutation, {
      phone,
      password,
    });

    if (response.errors) {
      throw new Error(response.errors[0]?.message || 'Ошибка аутентификации');
    }

    if (response.data?.authenticateUserWithPhoneAndPassword?.token) {
      this.token = response.data.authenticateUserWithPhoneAndPassword.token;
      localStorage.setItem(this.tokenStorageKey, this.token);
      return this.token;
    }

    throw new Error('Не удалось получить токен авторизации');
  }

  /**
   * Проверка текущего пользователя
   */
  async getAuthenticatedUser() {
    const query = `
      query {
        authenticatedUser {
          id
          name
          email
          phone
          type
        }
      }
    `;

    const response = await this.request(query);
    return response.data;
  }

  /**
   * Получение списка заявок (tickets)
   * В Doma AI заявки могут называться Ticket, ServiceRequest или аналогично
   */
  async getTickets(filters?: {
    status?: string;
    assignee?: string;
    property?: string;
    limit?: number;
    skip?: number;
  }): Promise<DomaTicket[]> {
    // Пробуем разные возможные названия типов заявок в Doma AI
    // В зависимости от вашей схемы это может быть Ticket, ServiceRequest, Request и т.д.
    
    const query = `
      query GetTickets($where: TicketWhereInput, $first: Int, $skip: Int) {
        objs: tickets(where: $where, first: $first, skip: $skip, orderBy: createdAt_DESC) {
          id
          number
          status {
            id
            name
            type
          }
          details
          description
          createdAt
          updatedAt
          deadline
          property {
            id
            address
            unitName
          }
          client {
            id
            name
            phone
          }
          assignee {
            id
            name
          }
          category {
            id
            name
          }
        }
      }
    `;

    const variables: any = {
      first: filters?.limit || 100,
      skip: filters?.skip || 0,
    };

    if (filters) {
      variables.where = {};
      if (filters.status) {
        variables.where.status = { id: filters.status };
      }
      if (filters.assignee) {
        variables.where.assignee = { id: filters.assignee };
      }
      if (filters.property) {
        variables.where.property = { id: filters.property };
      }
    }

    try {
      const response = await this.request<{ objs: DomaTicket[] }>(query, variables);
      
      if (response.errors) {
        console.warn('[DomaGraphQLClient] Ошибка при получении заявок:', response.errors);
        // Пробуем альтернативный запрос
        return await this.getTicketsAlternative(filters);
      }

      return response.data?.objs || [];
    } catch (error) {
      console.error('[DomaGraphQLClient] Ошибка при запросе заявок:', error);
      // Пробуем альтернативный запрос
      return await this.getTicketsAlternative(filters);
    }
  }

  /**
   * Альтернативный запрос заявок (если основная схема не работает)
   */
  private async getTicketsAlternative(filters?: any): Promise<DomaTicket[]> {
    // Пробуем запрос через ServiceRequest или другие возможные типы
    const alternativeQueries = [
      // Вариант 1: ServiceRequest
      `
        query GetServiceRequests($where: ServiceRequestWhereInput, $first: Int, $skip: Int) {
          objs: serviceRequests(where: $where, first: $first, skip: $skip, orderBy: createdAt_DESC) {
            id
            number
            status {
              id
              name
              type
            }
            details
            description
            createdAt
            updatedAt
            deadline
            property {
              id
              address
              unitName
            }
            client {
              id
              name
              phone
            }
            assignee {
              id
              name
            }
            category {
              id
              name
            }
          }
        }
      `,
      // Вариант 2: Request
      `
        query GetRequests($where: RequestWhereInput, $first: Int, $skip: Int) {
          objs: requests(where: $where, first: $first, skip: $skip, orderBy: createdAt_DESC) {
            id
            number
            status {
              id
              name
              type
            }
            details
            description
            createdAt
            updatedAt
            deadline
            property {
              id
              address
              unitName
            }
            client {
              id
              name
              phone
            }
            assignee {
              id
              name
            }
            category {
              id
              name
            }
          }
        }
      `,
    ];

    for (const query of alternativeQueries) {
      try {
        const variables: any = {
          first: filters?.limit || 100,
          skip: filters?.skip || 0,
        };

        if (filters) {
          variables.where = {};
          if (filters.status) {
            variables.where.status = { id: filters.status };
          }
        }

        const response = await this.request<{ objs: DomaTicket[] }>(query, variables);
        
        if (response.data?.objs) {
          return response.data.objs;
        }
      } catch (error) {
        console.warn('[DomaGraphQLClient] Альтернативный запрос не сработал:', error);
        continue;
      }
    }

    return [];
  }

  /**
   * Базовый метод для выполнения GraphQL запросов
   */
  private async request<T>(
    query: string,
    variables?: Record<string, any>
  ): Promise<DomaGraphQLResponse<T>> {
    if (!this.apiUrl) {
      throw new Error('VITE_DOMA_AI_API_URL не настроен. Укажите URL вашего инстанса Doma AI.');
    }

    const headers: HeadersInit = {
      'Content-Type': 'application/json',
    };
    const portalToken = getAuthToken();
    if (portalToken) {
      (headers as Record<string, string>)['Authorization'] = `Bearer ${portalToken}`;
    }

    // Важно: авторизационный токен к Doma AI больше не отправляем из браузера напрямую.
    // Вместо этого передаём его в config.body на наш backend-прокси.

    // Читаем актуальные настройки интеграции
    const settings = settingsService.getDomaAISettings();

    const config = {
      apiUrl: settings?.apiUrl,
      token: settings?.token || this.token || null,
    };

    try {
      const bodyPayload = {
        query,
        variables: variables || {},
        config,
      };

      console.log('[DomaGraphQLClient] Запрос к Doma AI', {
        url: this.apiUrl,
        hasToken: !!this.token,
        // Лучше не логировать полный запрос, чтобы не засорять консоль,
        // показываем только первые символы
        queryPreview: query.slice(0, 100),
      });

      const response = await fetch(this.apiUrl, {
        method: 'POST',
        headers,
        body: JSON.stringify(bodyPayload),
      });

      const rawText = await response.text();

      console.log('[DomaGraphQLClient] Ответ Doma AI', {
        status: response.status,
        ok: response.ok,
        length: rawText.length,
        preview: rawText.slice(0, 300),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      if (!rawText) {
        // Пустой ответ от Doma AI
        return {} as DomaGraphQLResponse<T>;
      }

      const result: DomaGraphQLResponse<T> = JSON.parse(rawText);

      // Если получили ошибку авторизации, очищаем токен
      if (result.errors?.some(e => e.message.includes('auth') || e.message.includes('unauthorized'))) {
        this.token = null;
        localStorage.removeItem(this.tokenStorageKey);
        throw new Error('Требуется повторная авторизация');
      }

      return result;
    } catch (error) {
      console.error('[DomaGraphQLClient] Ошибка запроса:', error);
      throw error;
    }
  }

  /**
   * Установка токена вручную (если токен получен извне)
   */
  setToken(token: string): void {
    this.token = token;
    localStorage.setItem(this.tokenStorageKey, token);
  }

  /**
   * Очистка токена (выход)
   */
  clearToken(): void {
    this.token = null;
    localStorage.removeItem(this.tokenStorageKey);
  }

  /**
   * Проверка наличия токена
   */
  hasToken(): boolean {
    return !!this.token;
  }

  /**
   * Обновление заявки (ticket) в Doma AI
   * @param ticketId - ID заявки в Doma AI (UUID)
   * @param data - Данные для обновления
   */
  async updateTicket(
    ticketId: string,
    data: {
      status?: { id?: string; type?: string };
      statusReason?: string;
      deferredUntil?: string;
      lastCommentWithResidentTypeAt?: string;
    }
  ): Promise<{ id: string; number: string }> {
    const mutation = `
      mutation UpdateTicket($id: ID!, $data: TicketUpdateInput!) {
        obj: updateTicket(id: $id, data: $data) {
          id
          number
          status {
            id
            name
            type
          }
          updatedAt
        }
      }
    `;

    const variables: any = {
      id: ticketId,
      data: {},
    };

    // Маппинг локальных статусов в статусы Doma.AI
    const statusTypeMap: Record<string, string> = {
      new: 'new_or_reopened',
      in_progress: 'processing',
      deferred: 'deferred',
      done: 'completed',
      canceled: 'canceled',
    };

    if (data.status?.type) {
      const domaStatusType = statusTypeMap[data.status.type] || data.status.type;
      variables.data.status = { type: domaStatusType };
    } else if (data.status?.id) {
      variables.data.status = { id: data.status.id };
    }

    if (data.statusReason) {
      variables.data.statusReason = data.statusReason;
    }

    if (data.deferredUntil) {
      variables.data.deferredUntil = data.deferredUntil;
    }

    if (data.lastCommentWithResidentTypeAt) {
      variables.data.lastCommentWithResidentTypeAt = data.lastCommentWithResidentTypeAt;
    }

    // Устанавливаем дату обновления статуса
    variables.data.statusUpdatedAt = new Date().toISOString();

    const response = await this.request<{ obj: { id: string; number: string } }>(mutation, variables);

    if (response.errors) {
      throw new Error(response.errors[0]?.message || 'Ошибка при обновлении заявки');
    }

    if (!response.data?.obj) {
      throw new Error('Не удалось обновить заявку');
    }

    return response.data.obj;
  }
}

export const domaGraphQLClient = new DomaGraphQLClient();
