import { getDb } from '../db'
import { Context } from '../types/context'
import { GraphQLError } from 'graphql'
import { logger } from '../lib/logger'

export interface ForumCategory {
  id: string
  name: string
  description: string | null
  slug: string
  postCount: number
  lastPostAt: Date | null
  createdAt: Date
}

export interface ForumPost {
  id: string
  categoryId: string
  authorId: string
  title: string
  content: string
  views: number
  replyCount: number
  isPinned: boolean
  isLocked: boolean
  lastReplyAt: Date | null
  createdAt: Date
  updatedAt: Date
}

export interface ForumReply {
  id: string
  postId: string
  authorId: string
  content: string
  isSolution: boolean
  createdAt: Date
  updatedAt: Date
}

export async function getForumCategories(): Promise<ForumCategory[]> {
  const db = getDb()
  const result = await db.query(`
    SELECT 
      c.id,
      c.name,
      c.description,
      c.slug,
      COUNT(DISTINCT p.id) as post_count,
      MAX(p.created_at) as last_post_at,
      c.created_at
    FROM forum_categories c
    LEFT JOIN forum_posts p ON p.category_id = c.id
    GROUP BY c.id, c.name, c.description, c.slug, c.created_at
    ORDER BY c.name
  `)

  return result.rows.map(row => ({
    id: row.id,
    name: row.name,
    description: row.description,
    slug: row.slug,
    postCount: parseInt(row.post_count) || 0,
    lastPostAt: row.last_post_at ? new Date(row.last_post_at) : null,
    createdAt: new Date(row.created_at),
  }))
}

export async function getForumCategory(id: string): Promise<ForumCategory | null> {
  const db = getDb()
  const result = await db.query(
    'SELECT * FROM forum_categories WHERE id = $1',
    [id]
  )

  if (result.rows.length === 0) {
    return null
  }

  const row = result.rows[0]
  const postCountResult = await db.query(
    'SELECT COUNT(*) as count FROM forum_posts WHERE category_id = $1',
    [id]
  )
  const lastPostResult = await db.query(
    'SELECT MAX(created_at) as last_post_at FROM forum_posts WHERE category_id = $1',
    [id]
  )

  return {
    id: row.id,
    name: row.name,
    description: row.description,
    slug: row.slug,
    postCount: parseInt(postCountResult.rows[0]?.count) || 0,
    lastPostAt: lastPostResult.rows[0]?.last_post_at ? new Date(lastPostResult.rows[0].last_post_at) : null,
    createdAt: new Date(row.created_at),
  }
}

export async function getForumPosts(filter: {
  categoryId?: string
  authorId?: string
  search?: string
  limit?: number
  offset?: number
}): Promise<ForumPost[]> {
  const db = getDb()
  const conditions: string[] = []
  const params: any[] = []
  let paramIndex = 1

  if (filter.categoryId) {
    conditions.push(`p.category_id = $${paramIndex++}`)
    params.push(filter.categoryId)
  }

  if (filter.authorId) {
    conditions.push(`p.author_id = $${paramIndex++}`)
    params.push(filter.authorId)
  }

  if (filter.search) {
    conditions.push(`(p.title ILIKE $${paramIndex} OR p.content ILIKE $${paramIndex})`)
    params.push(`%${filter.search}%`)
    paramIndex++
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
  const limit = filter.limit || 50
  const offset = filter.offset || 0

  const result = await db.query(`
    SELECT 
      p.*,
      COUNT(DISTINCT r.id) as reply_count,
      MAX(r.created_at) as last_reply_at
    FROM forum_posts p
    LEFT JOIN forum_replies r ON r.post_id = p.id
    ${whereClause}
    GROUP BY p.id
    ORDER BY p.is_pinned DESC, p.created_at DESC
    LIMIT $${paramIndex++} OFFSET $${paramIndex++}
  `, [...params, limit, offset])

  return result.rows.map(row => ({
    id: row.id,
    categoryId: row.category_id,
    authorId: row.author_id,
    title: row.title,
    content: row.content,
    views: row.views || 0,
    replyCount: parseInt(row.reply_count) || 0,
    isPinned: row.is_pinned || false,
    isLocked: row.is_locked || false,
    lastReplyAt: row.last_reply_at ? new Date(row.last_reply_at) : null,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }))
}

export async function getForumPost(id: string): Promise<ForumPost | null> {
  const db = getDb()
  const result = await db.query(`
    SELECT 
      p.*,
      COUNT(DISTINCT r.id) as reply_count,
      MAX(r.created_at) as last_reply_at
    FROM forum_posts p
    LEFT JOIN forum_replies r ON r.post_id = p.id
    WHERE p.id = $1
    GROUP BY p.id
  `, [id])

  if (result.rows.length === 0) {
    return null
  }

  const row = result.rows[0]

  // Increment view count
  await db.query(
    'UPDATE forum_posts SET views = views + 1 WHERE id = $1',
    [id]
  )

  return {
    id: row.id,
    categoryId: row.category_id,
    authorId: row.author_id,
    title: row.title,
    content: row.content,
    views: (row.views || 0) + 1,
    replyCount: parseInt(row.reply_count) || 0,
    isPinned: row.is_pinned || false,
    isLocked: row.is_locked || false,
    lastReplyAt: row.last_reply_at ? new Date(row.last_reply_at) : null,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function getForumReplies(postId: string): Promise<ForumReply[]> {
  const db = getDb()
  const result = await db.query(
    'SELECT * FROM forum_replies WHERE post_id = $1 ORDER BY created_at ASC',
    [postId]
  )

  return result.rows.map(row => ({
    id: row.id,
    postId: row.post_id,
    authorId: row.author_id,
    content: row.content,
    isSolution: row.is_solution || false,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }))
}

export async function createForumPost(
  context: Context,
  input: { categoryId: string; title: string; content: string }
): Promise<ForumPost> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  const result = await db.query(
    `INSERT INTO forum_posts (category_id, author_id, title, content, created_at, updated_at)
     VALUES ($1, $2, $3, $4, NOW(), NOW())
     RETURNING *`,
    [input.categoryId, context.user.id, input.title, input.content]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    categoryId: row.category_id,
    authorId: row.author_id,
    title: row.title,
    content: row.content,
    views: 0,
    replyCount: 0,
    isPinned: false,
    isLocked: false,
    lastReplyAt: null,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function updateForumPost(
  context: Context,
  id: string,
  input: { title?: string; content?: string }
): Promise<ForumPost> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check ownership
  const postResult = await db.query(
    'SELECT author_id FROM forum_posts WHERE id = $1',
    [id]
  )

  if (postResult.rows.length === 0) {
    throw new GraphQLError('Post not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  if (postResult.rows[0].author_id !== context.user.id && context.user.role !== 'ADMIN') {
    throw new GraphQLError('Permission denied', {
      extensions: { code: 'FORBIDDEN' },
    })
  }

  const updates: string[] = []
  const params: any[] = []
  let paramIndex = 1

  if (input.title) {
    updates.push(`title = $${paramIndex++}`)
    params.push(input.title)
  }

  if (input.content) {
    updates.push(`content = $${paramIndex++}`)
    params.push(input.content)
  }

  updates.push(`updated_at = NOW()`)
  params.push(id)

  const result = await db.query(
    `UPDATE forum_posts SET ${updates.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
    params
  )

  const row = result.rows[0]
  const replyCountResult = await db.query(
    'SELECT COUNT(*) as count FROM forum_replies WHERE post_id = $1',
    [id]
  )

  return {
    id: row.id,
    categoryId: row.category_id,
    authorId: row.author_id,
    title: row.title,
    content: row.content,
    views: row.views || 0,
    replyCount: parseInt(replyCountResult.rows[0]?.count) || 0,
    isPinned: row.is_pinned || false,
    isLocked: row.is_locked || false,
    lastReplyAt: null,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function deleteForumPost(context: Context, id: string): Promise<boolean> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check ownership or admin
  const postResult = await db.query(
    'SELECT author_id FROM forum_posts WHERE id = $1',
    [id]
  )

  if (postResult.rows.length === 0) {
    throw new GraphQLError('Post not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  if (postResult.rows[0].author_id !== context.user.id && context.user.role !== 'ADMIN') {
    throw new GraphQLError('Permission denied', {
      extensions: { code: 'FORBIDDEN' },
    })
  }

  await db.query('DELETE FROM forum_replies WHERE post_id = $1', [id])
  await db.query('DELETE FROM forum_posts WHERE id = $1', [id])

  return true
}

export async function createForumReply(
  context: Context,
  input: { postId: string; content: string }
): Promise<ForumReply> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  const result = await db.query(
    `INSERT INTO forum_replies (post_id, author_id, content, created_at, updated_at)
     VALUES ($1, $2, $3, NOW(), NOW())
     RETURNING *`,
    [input.postId, context.user.id, input.content]
  )

  // Update post's last_reply_at
  await db.query(
    'UPDATE forum_posts SET last_reply_at = NOW(), updated_at = NOW() WHERE id = $1',
    [input.postId]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    postId: row.post_id,
    authorId: row.author_id,
    content: row.content,
    isSolution: row.is_solution || false,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function updateForumReply(
  context: Context,
  id: string,
  input: { content: string }
): Promise<ForumReply> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check ownership
  const replyResult = await db.query(
    'SELECT author_id FROM forum_replies WHERE id = $1',
    [id]
  )

  if (replyResult.rows.length === 0) {
    throw new GraphQLError('Reply not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  if (replyResult.rows[0].author_id !== context.user.id && context.user.role !== 'ADMIN') {
    throw new GraphQLError('Permission denied', {
      extensions: { code: 'FORBIDDEN' },
    })
  }

  const result = await db.query(
    'UPDATE forum_replies SET content = $1, updated_at = NOW() WHERE id = $2 RETURNING *',
    [input.content, id]
  )

  const row = result.rows[0]
  return {
    id: row.id,
    postId: row.post_id,
    authorId: row.author_id,
    content: row.content,
    isSolution: row.is_solution || false,
    createdAt: new Date(row.created_at),
    updatedAt: new Date(row.updated_at),
  }
}

export async function deleteForumReply(context: Context, id: string): Promise<boolean> {
  if (!context.user) {
    throw new GraphQLError('Authentication required', {
      extensions: { code: 'UNAUTHENTICATED' },
    })
  }

  const db = getDb()
  
  // Check ownership or admin
  const replyResult = await db.query(
    'SELECT author_id FROM forum_replies WHERE id = $1',
    [id]
  )

  if (replyResult.rows.length === 0) {
    throw new GraphQLError('Reply not found', {
      extensions: { code: 'NOT_FOUND' },
    })
  }

  if (replyResult.rows[0].author_id !== context.user.id && context.user.role !== 'ADMIN') {
    throw new GraphQLError('Permission denied', {
      extensions: { code: 'FORBIDDEN' },
    })
  }

  await db.query('DELETE FROM forum_replies WHERE id = $1', [id])

  return true
}

