import { useState, useEffect, useCallback, useRef } from "react"
import {
  GitHubRepository,
  GitHubStats,
  RateLimitInfo,
  StarHistory,
  Milestone,
} from "./types"
import {
  fetchUserRepositories,
  fetchRepository,
  fetchContributorsCount,
  fetchStarHistory,
  calculateStats,
  getRateLimitInfo,
  clearCache,
} from "./github-api"

interface UseGitHubDataOptions {
  username?: string
  repository?: string
  repositories?: string[]
  token?: string
  autoRefresh?: boolean
  refreshInterval?: number
  sortBy?: string
  maxItems?: number
  onError?: (error: Error) => void
  onDataUpdate?: (stats: GitHubStats) => void
  onMilestoneReached?: (milestone: Milestone) => void
  milestones?: number[]
  // For docs mode optimizations
  docsMode?: boolean
  mockDataFallback?: boolean
  forceMockData?: boolean // Force mock data instead of API
}

export function useGitHubData({
  username,
  repository,
  repositories,
  token,
  autoRefresh = false,
  refreshInterval = 300000,
  sortBy = "stars",
  maxItems,
  onError,
  onDataUpdate,
  onMilestoneReached,
  milestones = [10, 50, 100, 500, 1000, 5000, 10000],
  docsMode = false,
  mockDataFallback = true,
  forceMockData = false,
}: UseGitHubDataOptions) {
  // Docs mode detection
  const isDocsMode = docsMode || (typeof window !== "undefined" && 
    (window.location.pathname.includes("/docs/") || 
     window.location.pathname.includes("/components/")))
  
  // Disable autoRefresh in docs mode
  const effectiveAutoRefresh = isDocsMode ? false : autoRefresh
  const [repos, setRepos] = useState<GitHubRepository[]>([])
  const [stats, setStats] = useState<GitHubStats | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [rateLimitInfo, setRateLimitInfo] = useState<RateLimitInfo | null>(null)
  const [lastUpdated, setLastUpdated] = useState<Date | null>(null)
  
  const refreshTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
  const previousStarsRef = useRef<Map<string, number>>(new Map())
  const errorCountRef = useRef<number>(0) // Hata sayısını takip et
  const maxErrorCount = isDocsMode ? 1 : 2 // Fewer retries in docs mode
  const hasInitialFetchedRef = useRef(false) // İlk fetch yapıldı mı?
  const docsDataCacheRef = useRef<GitHubRepository[] | null>(null) // Docs mode cache

  // Store checkMilestones function as ref - this way it won't be recreated on every render
  const milestonesRef = useRef(milestones)
  const onMilestoneReachedRef = useRef(onMilestoneReached)
  
  // Ref'leri güncelle
  useEffect(() => {
    milestonesRef.current = milestones
  }, [milestones])
  
  useEffect(() => {
    onMilestoneReachedRef.current = onMilestoneReached
  }, [onMilestoneReached])

  const checkMilestones = useCallback((repos: GitHubRepository[]) => {
    if (!onMilestoneReachedRef.current) return

    repos.forEach(repo => {
      const previousStars = previousStarsRef.current.get(repo.full_name) || 0
      const currentStars = repo.stargazers_count

      milestonesRef.current.forEach(milestone => {
        if (previousStars < milestone && currentStars >= milestone) {
          onMilestoneReachedRef.current?.({
            count: milestone,
            reached: true,
            date: new Date().toISOString(),
            celebration: true,
          })
        }
      })

      previousStarsRef.current.set(repo.full_name, currentStars)
    })
  }, []) // Boş dependency array - fonksiyon asla yeniden oluşturulmaz

  const fetchData = useCallback(async () => {
    // If forceMockData is true, always return mock data
    if (forceMockData) {
      console.log("[Mock Mode] Using mock data")
      const mockData = getMockGitHubData(username, repository, repositories)
      setRepos(mockData)
      const calculatedStats = calculateStats(mockData)
      setStats(calculatedStats)
      setError(null)
      setLoading(false)
      return
    }

    // Docs modunda ve daha önce fetch yapıldıysa, cache'den döndür
    if (isDocsMode && hasInitialFetchedRef.current && docsDataCacheRef.current) {
      console.log("[Docs Mode] Returning cached data, skipping API request")
      setRepos(docsDataCacheRef.current)
      const calculatedStats = calculateStats(docsDataCacheRef.current)
      setStats(calculatedStats)
      setLoading(false)
      return
    }

    // Hata limiti aşıldıysa istek yapma
    if (errorCountRef.current >= maxErrorCount) {
      console.warn("Maximum error count reached. Stopping requests.")
      
      // Show mock data if in docs mode and mockDataFallback is active
      if (isDocsMode && mockDataFallback) {
        const mockData = getMockGitHubData(username, repository, repositories)
        setRepos(mockData)
        const calculatedStats = calculateStats(mockData)
        setStats(calculatedStats)
        setError(null)
      } else {
        setError("Maximum retry limit exceeded. Please check your configuration.")
      }
      
      setLoading(false)
      return
    }

    // Don't make requests if required info is missing
    const hasValidInput = 
      (username && repository) || // Tek repository modu
      (username && repositories && repositories.length > 0) || // Çoklu repository modu
      (repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) || // Full path repositories
      username // Kullanıcının tüm repositoryleri

    if (!hasValidInput) {
      console.warn("No valid input provided. Skipping API request.")
      setLoading(false)
      setError(null)
      setRepos([])
      setStats(null)
      return
    }

    try {
      setLoading(true)
      setError(null)

      // Check rate limit first
      try {
        const rateLimit = await getRateLimitInfo(token)
        setRateLimitInfo(rateLimit)

        if (rateLimit.remaining < 10) {
          console.warn(`Low GitHub API rate limit: ${rateLimit.remaining} requests remaining`)
        }
      } catch (error) {
        console.error("Failed to fetch rate limit:", error)
      }

      let fetchedRepos: GitHubRepository[] = []

      // Single repository mode
      if (repository && username) {
        const repo = await fetchRepository(username, repository, token)
        fetchedRepos = [repo]
      }
      // Multiple specific repositories with full paths
      else if (repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) {
        const repoPromises = repositories.map(fullPath => {
          const [owner, name] = fullPath.split('/')
          return fetchRepository(owner, name, token)
        })
        fetchedRepos = await Promise.all(repoPromises)
      }
      // Multiple specific repositories with username
      else if (repositories && repositories.length > 0 && username) {
        const repoPromises = repositories.map(repoName =>
          fetchRepository(username, repoName, token)
        )
        fetchedRepos = await Promise.all(repoPromises)
      }
      // All user repositories
      else if (username) {
        fetchedRepos = await fetchUserRepositories(username, token, {
          sort: sortBy,
          per_page: 100,
        })
      }

      // Sort repositories
      fetchedRepos.sort((a, b) => {
        switch (sortBy) {
          case "stars":
            return b.stargazers_count - a.stargazers_count
          case "forks":
            return b.forks_count - a.forks_count
          case "updated":
            return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
          case "created":
            return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
          case "name":
            return a.name.localeCompare(b.name)
          case "issues":
            return b.open_issues_count - a.open_issues_count
          default:
            return 0
        }
      })

      // Limit results
      if (maxItems && maxItems > 0) {
        fetchedRepos = fetchedRepos.slice(0, maxItems)
      }

      // Fetch additional data for detailed view
      const enhancedRepos = await Promise.all(
        fetchedRepos.map(async repo => {
          try {
            const contributorsCount = await fetchContributorsCount(
              repo.owner.login,
              repo.name,
              token
            )
            return { ...repo, contributors_count: contributorsCount }
          } catch (error) {
            console.error(`Failed to fetch contributors for ${repo.full_name}:`, error)
            return repo
          }
        })
      )

      setRepos(enhancedRepos)
      
      // Calculate statistics
      const calculatedStats = calculateStats(enhancedRepos)
      setStats(calculatedStats)
      
      // Check milestones
      checkMilestones(enhancedRepos)
      
      // Notify data update
      if (onDataUpdate) {
        onDataUpdate(calculatedStats)
      }
      
      setLastUpdated(new Date())
      // Reset error counter on success
      errorCountRef.current = 0
      
      // Cache successful data in docs mode
      if (isDocsMode) {
        hasInitialFetchedRef.current = true
        docsDataCacheRef.current = enhancedRepos
      }
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : "Failed to fetch data"
      setError(errorMessage)
      
      // Hata sayacını artır
      errorCountRef.current += 1
      console.error(`GitHub API error (${errorCountRef.current}/${maxErrorCount}):`, errorMessage)
      
      // Show mock data if in docs mode and mockDataFallback is active
      if (isDocsMode && mockDataFallback && !hasInitialFetchedRef.current) {
        console.warn("[Docs Mode] API failed, using mock data")
        const mockData = getMockGitHubData(username, repository, repositories)
        setRepos(mockData)
        const calculatedStats = calculateStats(mockData)
        setStats(calculatedStats)
        setError(null)
        hasInitialFetchedRef.current = true
        docsDataCacheRef.current = mockData
      } else if (onError) {
        onError(err instanceof Error ? err : new Error(errorMessage))
      }
    } finally {
      setLoading(false)
    }
  }, [
    username,
    repository,
    repositories?.join(','), // Convert array to string to keep reference stable
    token,
    sortBy,
    maxItems,
    checkMilestones, // Now stable
    onDataUpdate,
    onError,
    isDocsMode,
    mockDataFallback,
    forceMockData,
  ])

  // Initial fetch
  useEffect(() => {
    // Only fetch if there's valid input
    const hasValidInput = 
      (username && repository) || 
      (username && repositories && repositories.length > 0) || 
      (repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) || 
      username

    if (hasValidInput) {
      fetchData()
    } else {
      setLoading(false)
    }
  }, [fetchData])

  // Auto-refresh
  useEffect(() => {
    // Completely disable auto-refresh in docs mode
    if (!effectiveAutoRefresh) return

    const scheduleRefresh = () => {
      refreshTimeoutRef.current = setTimeout(() => {
        fetchData()
        scheduleRefresh()
      }, refreshInterval)
    }

    scheduleRefresh()

    return () => {
      if (refreshTimeoutRef.current) {
        clearTimeout(refreshTimeoutRef.current)
      }
    }
  }, [effectiveAutoRefresh, refreshInterval, fetchData])

  const refresh = useCallback(() => {
    // Limit refresh in docs mode
    if (isDocsMode && hasInitialFetchedRef.current) {
      console.warn("[Docs Mode] Refresh disabled after initial fetch")
      return Promise.resolve()
    }
    
    // Hata limiti aşıldıysa refresh yapma
    if (errorCountRef.current >= maxErrorCount) {
      console.warn("Cannot refresh: maximum error count reached")
      return Promise.resolve()
    }
    
    clearCache()
    return fetchData()
  }, [fetchData, isDocsMode])

  return {
    repos,
    stats,
    loading,
    error,
    rateLimitInfo,
    lastUpdated,
    refresh,
  }
}

// Hook for star history
export function useStarHistory(
  owner: string,
  repo: string,
  token?: string
) {
  const [history, setHistory] = useState<StarHistory[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const fetchHistory = async () => {
      try {
        setLoading(true)
        setError(null)
        const data = await fetchStarHistory(owner, repo, token)
        setHistory(data)
      } catch (err) {
        setError(err instanceof Error ? err.message : "Failed to fetch star history")
      } finally {
        setLoading(false)
      }
    }

    if (owner && repo) {
      fetchHistory()
    }
  }, [owner, repo, token])

  return { history, loading, error }
}

// Hook for notifications
export function useGitHubNotifications(enabled: boolean = true) {
  const [permission, setPermission] = useState<NotificationPermission>("default")

  useEffect(() => {
    if (!enabled || typeof window === "undefined" || !("Notification" in window)) {
      return
    }

    setPermission(Notification.permission)

    if (Notification.permission === "default") {
      Notification.requestPermission().then(setPermission)
    }
  }, [enabled])

  const notify = useCallback(
    (title: string, options?: NotificationOptions) => {
      if (!enabled || permission !== "granted") return

      try {
        new Notification(title, {
          icon: "/icon-192x192.png",
          badge: "/icon-192x192.png",
          ...options,
        })
      } catch (error) {
        console.error("Failed to show notification:", error)
      }
    },
    [enabled, permission]
  )

  return { permission, notify }
}

// Mock data generator for docs mode
function getMockGitHubData(
  username?: string,
  repository?: string,
  repositories?: string[]
): GitHubRepository[] {
  const defaultRepos: GitHubRepository[] = [
    {
      id: 1,
      name: repository || "awesome-project",
      full_name: `${username || "moonui"}/${repository || "awesome-project"}`,
      description: "An amazing open source project with great features",
      html_url: `https://github.com/${username || "moonui"}/${repository || "awesome-project"}`,
      homepage: "https://awesome-project.dev",
      stargazers_count: 12453,
      watchers_count: 543,
      forks_count: 2341,
      language: "TypeScript",
      topics: ["react", "ui", "components", "typescript"],
      created_at: "2022-01-15T10:30:00Z",
      updated_at: new Date().toISOString(),
      pushed_at: new Date().toISOString(),
      size: 4567,
      open_issues_count: 23,
      license: {
        key: "mit",
        name: "MIT License",
        spdx_id: "MIT",
        url: "https://api.github.com/licenses/mit",
      },
      owner: {
        login: username || "moonui",
        avatar_url: `https://github.com/${username || "moonui"}.png`,
        html_url: `https://github.com/${username || "moonui"}`,
        type: "Organization",
      },
      contributors_count: 89,
    },
  ]

  if (repositories && repositories.length > 0) {
    return repositories.map((repo, index) => {
      const [owner, name] = repo.includes('/') ? repo.split('/') : [username || "moonui", repo]
      return {
        ...defaultRepos[0],
        id: index + 1,
        name: name,
        full_name: `${owner}/${name}`,
        html_url: `https://github.com/${owner}/${name}`,
        stargazers_count: Math.floor(Math.random() * 20000) + 1000,
        forks_count: Math.floor(Math.random() * 3000) + 100,
        watchers_count: Math.floor(Math.random() * 1000) + 50,
        language: ["TypeScript", "JavaScript", "Python", "Go", "Rust"][index % 5],
        owner: {
          login: owner,
          avatar_url: `https://github.com/${owner}.png`,
          html_url: `https://github.com/${owner}`,
          type: "Organization",
        },
      }
    })
  }

  return defaultRepos
}