import { GraphQLError } from 'graphql'

import { prisma } from '../../../lib/prisma'
import { Context } from '../../context'
import { DomainResolvers } from '../shared/types'

// Messaging Domain Resolvers - изолированная логика сообщений и бесед
export const messagingResolvers: DomainResolvers = {
  Query: {
    // Получение сообщений с контрагентом
    messages: async (
      _: unknown,
      args: { counterpartyId: string; limit?: number; offset?: number },
      context: Context,
    ) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      const limit = args.limit || 50
      const offset = args.offset || 0

      const messages = await prisma.message.findMany({
        where: {
          OR: [
            {
              senderOrganizationId: currentUser.organization.id,
              receiverOrganizationId: args.counterpartyId,
            },
            {
              senderOrganizationId: args.counterpartyId,
              receiverOrganizationId: currentUser.organization.id,
            },
          ],
        },
        include: {
          senderOrganization: {
            include: {
              users: true,
            },
          },
          receiverOrganization: {
            include: {
              users: true,
            },
          },
        },
        orderBy: {
          createdAt: 'desc',
        },
        take: limit,
        skip: offset,
      })

      return messages.reverse() // Возвращаем в прямом порядке (старые -> новые)
    },

    // Получение списка бесед (разговоров) 
    conversations: async (_: unknown, __: unknown, context: Context) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // Получаем всех контрагентов
      const counterparties = await prisma.counterparty.findMany({
        where: { organizationId: currentUser.organization.id },
        include: {
          counterparty: {
            include: {
              users: true,
            },
          },
        },
      })

      // Для каждого контрагента получаем последнее сообщение и количество непрочитанных
      const conversations = await Promise.all(
        counterparties.map(async (cp) => {
          // Последнее сообщение
          const lastMessage = await prisma.message.findFirst({
            where: {
              OR: [
                {
                  senderOrganizationId: currentUser.organization!.id,
                  receiverOrganizationId: cp.counterpartyId,
                },
                {
                  senderOrganizationId: cp.counterpartyId,
                  receiverOrganizationId: currentUser.organization!.id,
                },
              ],
            },
            orderBy: {
              createdAt: 'desc',
            },
            include: {
              senderOrganization: {
                include: {
                  users: true,
                },
              },
              receiverOrganization: {
                include: {
                  users: true,
                },
              },
            },
          })

          // Количество непрочитанных сообщений от контрагента
          const unreadCount = await prisma.message.count({
            where: {
              senderOrganizationId: cp.counterpartyId,
              receiverOrganizationId: currentUser.organization!.id,
              isRead: false,
            },
          })

          return {
            id: `${currentUser.organization!.id}-${cp.counterpartyId}`,
            counterparty: cp.counterparty,
            lastMessage,
            unreadCount,
            updatedAt: lastMessage?.createdAt || cp.createdAt,
          }
        }),
      )

      // Сортируем по времени последнего сообщения
      return conversations.sort((a, b) => 
        new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
      )
    },
  },

  Mutation: {
    // Отправка текстового сообщения
    sendMessage: async (
      _: unknown,
      args: {
        receiverOrganizationId: string
        content?: string
        type?: 'TEXT' | 'VOICE'
      },
      context: Context,
    ) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // Проверяем, что получатель является контрагентом
      const isCounterparty = await prisma.counterparty.findFirst({
        where: {
          organizationId: currentUser.organization.id,
          counterpartyId: args.receiverOrganizationId,
        },
      })

      if (!isCounterparty) {
        throw new GraphQLError('Можно отправлять сообщения только контрагентам')
      }

      // Получаем организацию получателя
      const receiverOrganization = await prisma.organization.findUnique({
        where: { id: args.receiverOrganizationId },
      })

      if (!receiverOrganization) {
        throw new GraphQLError('Организация получателя не найдена')
      }

      // Создаем сообщение
      const message = await prisma.message.create({
        data: {
          content: args.content?.trim() || null,
          type: args.type || 'TEXT',
          senderId: context.user.id,
          senderOrganizationId: currentUser.organization.id,
          receiverOrganizationId: args.receiverOrganizationId,
        },
        include: {
          senderOrganization: {
            include: {
              users: true,
            },
          },
          receiverOrganization: {
            include: {
              users: true,
            },
          },
        },
      })

      return message
    },

    // Отправка голосового сообщения
    sendVoiceMessage: async (
      _: unknown,
      args: {
        receiverOrganizationId: string
        voiceUrl: string
        voiceDuration: number
      },
      context: Context,
    ) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // Проверяем, что получатель является контрагентом
      const isCounterparty = await prisma.counterparty.findFirst({
        where: {
          organizationId: currentUser.organization.id,
          counterpartyId: args.receiverOrganizationId,
        },
      })

      if (!isCounterparty) {
        throw new GraphQLError('Можно отправлять сообщения только контрагентам')
      }

      // Получаем организацию получателя
      const receiverOrganization = await prisma.organization.findUnique({
        where: { id: args.receiverOrganizationId },
      })

      if (!receiverOrganization) {
        throw new GraphQLError('Организация получателя не найдена')
      }

      // Создаем голосовое сообщение
      const message = await prisma.message.create({
        data: {
          content: 'Голосовое сообщение',
          type: 'VOICE',
          senderId: context.user.id,
          senderOrganizationId: currentUser.organization.id,
          receiverOrganizationId: args.receiverOrganizationId,
          voiceUrl: args.voiceUrl,
          voiceDuration: args.voiceDuration,
        },
        include: {
          senderOrganization: {
            include: {
              users: true,
            },
          },
          receiverOrganization: {
            include: {
              users: true,
            },
          },
        },
      })

      return message
    },

    // Отправка изображения
    sendImageMessage: async (
      _: unknown,
      args: {
        receiverOrganizationId: string
        fileUrl: string
        fileName: string
        fileSize: number
        fileType: string
      },
      context: Context,
    ) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // Проверяем, что получатель является контрагентом
      const isCounterparty = await prisma.counterparty.findFirst({
        where: {
          organizationId: currentUser.organization.id,
          counterpartyId: args.receiverOrganizationId,
        },
      })

      if (!isCounterparty) {
        throw new GraphQLError('Можно отправлять сообщения только контрагентам')
      }

      // Получаем организацию получателя
      const receiverOrganization = await prisma.organization.findUnique({
        where: { id: args.receiverOrganizationId },
      })

      if (!receiverOrganization) {
        throw new GraphQLError('Организация получателя не найдена')
      }

      // Создаем сообщение с изображением
      const message = await prisma.message.create({
        data: {
          content: `Изображение: ${args.fileName}`,
          type: 'IMAGE',
          senderId: context.user.id,
          senderOrganizationId: currentUser.organization.id,
          receiverOrganizationId: args.receiverOrganizationId,
          fileUrl: args.fileUrl,
          fileName: args.fileName,
          fileSize: args.fileSize,
          fileType: args.fileType,
        },
        include: {
          senderOrganization: {
            include: {
              users: true,
            },
          },
          receiverOrganization: {
            include: {
              users: true,
            },
          },
        },
      })

      return message
    },

    // Отправка файла
    sendFileMessage: async (
      _: unknown,
      args: {
        receiverOrganizationId: string
        fileUrl: string
        fileName: string
        fileSize: number
        fileType: string
      },
      context: Context,
    ) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // Проверяем, что получатель является контрагентом
      const isCounterparty = await prisma.counterparty.findFirst({
        where: {
          organizationId: currentUser.organization.id,
          counterpartyId: args.receiverOrganizationId,
        },
      })

      if (!isCounterparty) {
        throw new GraphQLError('Можно отправлять сообщения только контрагентам')
      }

      // Получаем организацию получателя
      const receiverOrganization = await prisma.organization.findUnique({
        where: { id: args.receiverOrganizationId },
      })

      if (!receiverOrganization) {
        throw new GraphQLError('Организация получателя не найдена')
      }

      // Создаем сообщение с файлом
      const message = await prisma.message.create({
        data: {
          content: `Файл: ${args.fileName}`,
          type: 'FILE',
          senderId: context.user.id,
          senderOrganizationId: currentUser.organization.id,
          receiverOrganizationId: args.receiverOrganizationId,
          fileUrl: args.fileUrl,
          fileName: args.fileName,
          fileSize: args.fileSize,
          fileType: args.fileType,
        },
        include: {
          senderOrganization: {
            include: {
              users: true,
            },
          },
          receiverOrganization: {
            include: {
              users: true,
            },
          },
        },
      })

      return message
    },

    // Отметка сообщений как прочитанных
    markMessagesAsRead: async (_: unknown, args: { conversationId: string }, context: Context) => {
      if (!context.user) {
        throw new GraphQLError('Требуется авторизация', {
          extensions: { code: 'UNAUTHENTICATED' },
        })
      }

      const currentUser = await prisma.user.findUnique({
        where: { id: context.user.id },
        include: { organization: true },
      })

      if (!currentUser?.organization) {
        throw new GraphQLError('У пользователя нет организации')
      }

      // conversationId имеет формат "currentOrgId-counterpartyId"
      const [, counterpartyId] = args.conversationId.split('-')

      if (!counterpartyId) {
        throw new GraphQLError('Неверный ID беседы')
      }

      // Помечаем все непрочитанные сообщения от контрагента как прочитанные
      await prisma.message.updateMany({
        where: {
          senderOrganizationId: counterpartyId,
          receiverOrganizationId: currentUser.organization.id,
          isRead: false,
        },
        data: {
          isRead: true,
        },
      })

      return true
    },
  },
}