import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { remark } from 'remark'
import remarkGfm from 'remark-gfm'
import { FrontMatter, Post } from './types/frontmatter'
import { generateExcerpt } from './utils'
import { remarkCopyImages } from './remark-copy-images'
import { remarkInternalLinks } from './remark-internal-links'

const POSTS_PATH = path.join(process.cwd(), 'content', 'blog')

export function sanitizePath(inputPath: string): string {
  const normalized = path.normalize(inputPath).replace(/^(\.\.[/\\])+/, '')
  if (normalized.includes('..') || path.isAbsolute(normalized)) {
    throw new Error('Invalid path')
  }

  // CRITICAL: Verify resolved path stays within content directory
  const resolvedPath = path.resolve(POSTS_PATH, normalized)
  const allowedBasePath = path.resolve(POSTS_PATH)

  if (!resolvedPath.startsWith(allowedBasePath)) {
    throw new Error('Path traversal attempt detected')
  }

  return normalized
}

export function calculateReadingTime(content: string): number {
  const wordsPerMinute = 200
  const words = content.trim().split(/\s+/).length
  return Math.ceil(words / wordsPerMinute)
}

export function validateFrontmatter(data: any): FrontMatter {
  if (!data.title || typeof data.title !== 'string') {
    throw new Error('Invalid title')
  }
  if (!data.description || typeof data.description !== 'string') {
    throw new Error('Invalid description')
  }
  if (!data.date || typeof data.date !== 'string') {
    throw new Error('Invalid date')
  }
  if (!data.author || typeof data.author !== 'string') {
    throw new Error('Invalid author')
  }
  if (!data.category || typeof data.category !== 'string') {
    throw new Error('Invalid category')
  }
  if (!Array.isArray(data.tags) || data.tags.length === 0 || data.tags.length > 3) {
    throw new Error('Tags must be array with 1-3 items')
  }

  return {
    title: data.title,
    description: data.description,
    date: data.date,
    author: data.author,
    category: data.category,
    tags: data.tags,
    image: data.image,
    draft: data.draft || false,
  }
}

export async function getPostBySlug(slug: string | string[]): Promise<Post | null> {
  const slugArray = Array.isArray(slug) ? slug : slug.split('/')
  const sanitized = slugArray.map(s => sanitizePath(s))
  const fullPath = path.join(POSTS_PATH, ...sanitized) + '.md'

  if (!fs.existsSync(fullPath)) {
    return null
  }

  const fileContents = fs.readFileSync(fullPath, 'utf8')
  const { data, content } = matter(fileContents)
  const frontmatter = validateFrontmatter(data)

  const processed = await remark()
    .use(remarkGfm)
    .use(remarkCopyImages, {
      contentDir: 'content/blog',
      publicDir: 'public/blog',
      currentSlug: sanitized.join('/'),
    })
    .use(remarkInternalLinks)
    .process(content)

  const processedContent = processed.toString()

  return {
    slug: sanitized.join('/'),
    frontmatter,
    content: processedContent,
    readingTime: calculateReadingTime(processedContent),
    excerpt: generateExcerpt(processedContent),
  }
}

export async function getAllPosts(includeContent = false): Promise<Post[]> {
  const posts: Post[] = []

  async function walkDir(dir: string, prefix = ''): Promise<void> {
    const files = fs.readdirSync(dir)

    for (const file of files) {
      const filePath = path.join(dir, file)
      const stat = fs.statSync(filePath)

      if (stat.isDirectory()) {
        await walkDir(filePath, prefix ? `${prefix}/${file}` : file)
      } else if (file.endsWith('.md')) {
        const slug = prefix ? `${prefix}/${file.replace(/\.md$/, '')}` : file.replace(/\.md$/, '')
        try {
          const post = await getPostBySlug(slug.split('/'))
          if (post && !post.frontmatter.draft) {
            posts.push(includeContent ? post : { ...post, content: '' })
          }
        } catch (error) {
          console.error(`Error loading post ${slug}:`, error)
        }
      }
    }
  }

  if (fs.existsSync(POSTS_PATH)) {
    await walkDir(POSTS_PATH)
  }

  return posts.sort(
    (a, b) => new Date(b.frontmatter.date).getTime() - new Date(a.frontmatter.date).getTime()
  )
}

export async function getRelatedPosts(currentSlug: string, limit = 3): Promise<Post[]> {
  const currentPost = await getPostBySlug(currentSlug)
  if (!currentPost) return []

  const allPosts = await getAllPosts(false)
  const { category, tags } = currentPost.frontmatter

  const scored = allPosts
    .filter(post => post.slug !== currentSlug)
    .map(post => {
      let score = 0
      if (post.frontmatter.category === category) score += 3
      score += post.frontmatter.tags.filter(tag => tags.includes(tag)).length * 2
      return { post, score }
    })
    .filter(({ score }) => score > 0)
    .sort((a, b) => b.score - a.score)

  return scored.slice(0, limit).map(({ post }) => post)
}

export function getAllPostSlugs(): string[][] {
  const slugs: string[][] = []

  function walkDir(dir: string, prefix: string[] = []): void {
    const files = fs.readdirSync(dir)

    for (const file of files) {
      const filePath = path.join(dir, file)
      const stat = fs.statSync(filePath)

      if (stat.isDirectory()) {
        walkDir(filePath, [...prefix, file])
      } else if (file.endsWith('.md')) {
        slugs.push([...prefix, file.replace(/\.md$/, '')])
      }
    }
  }

  if (fs.existsSync(POSTS_PATH)) {
    walkDir(POSTS_PATH)
  }

  return slugs
}
