import { Context } from 'koa'

import { config } from '@things-factory/env'
import { cacheService } from '@things-factory/cache-service'

import { WeatherType } from './types.js'
import { getGlobalWeatherData } from './open-meteo-adapter.js'
import { renderWeatherMap } from '../services/chrome-renderer.js'

/**
 * 전체 날씨 지도 이미지 컨트롤러
 */
export async function globalWeatherController(ctx: Context) {
  const type = ctx.params.type
  const forceRefresh = ctx.query.refresh === 'true'

  try {
    // 유효한 날씨 타입인지 확인
    if (!['temperature', 'humidity', 'wind', 'precipitation'].includes(type)) {
      ctx.status = 400
      ctx.body = {
        error: `유효하지 않은 날씨 타입: ${type}`,
        validTypes: ['temperature', 'humidity', 'wind', 'precipitation']
      }
      return
    }

    // 날씨 이미지 가져오기
    const imageBuffer = await getGlobalWeatherImage(type, forceRefresh)

    // 이미지 데이터 응답
    ctx.body = Buffer.from(imageBuffer)

    // 이미지 응답 헤더 설정
    ctx.status = 200
    ctx.set('Content-Type', 'image/png')
    ctx.set('Cache-Control', 'public, max-age=3600') // 1시간 캐싱
  } catch (error) {
    console.error(`날씨 지도 생성 오류 (${type}):`, error)
    ctx.status = 500
    ctx.body = {
      error: '날씨 지도 생성 중 오류가 발생했습니다',
      message: error.message
    }
  }
}

/**
 * 전체 날씨 이미지 가져오기
 * @param type 날씨 타입 (temperature, humidity, wind, precipitation)
 * @param forceRefresh 캐시 무시하고 새로 가져오기
 */
export async function getGlobalWeatherImage(type: WeatherType, forceRefresh: boolean = false): Promise<Buffer> {
  if (!['temperature', 'humidity', 'wind', 'precipitation'].includes(type)) {
    throw new Error(`유효하지 않은 날씨 타입: ${type}`)
  }

  // 캐시 유효 시간 (분)
  const cacheLifetime = config.get('WEATHER_CACHE_LIFETIME') || 60

  try {
    // 캐시에서 데이터 확인
    if (!forceRefresh) {
      const { value: cachedDataJson } = (await cacheService.getFromCache(`global-weather-image`, { type })) || {}

      // Buffer.from이 객체를 직접 처리할 수 없으므로 타입에 따라 적절하게 처리
      let cachedData = null
      if (cachedDataJson) {
        if (Buffer.isBuffer(cachedDataJson)) {
          cachedData = cachedDataJson
        } else if (typeof cachedDataJson === 'string') {
          // 문자열이면 버퍼로 변환
          cachedData = cachedDataJson
        } else if (Array.isArray(cachedDataJson)) {
          // 배열이면 버퍼로 변환
          cachedData = cachedDataJson
        } else if (typeof cachedDataJson === 'object') {
          // 객체인 경우 처리 (JSON.stringify된 버퍼일 수 있음)
          try {
            // JSON 문자열로 변환했다가 다시 파싱하면 배열로 변환될 수 있음
            if ((cachedDataJson.type = 'Buffer')) {
              cachedData = cachedDataJson.data
            }
          } catch (conversionError) {
            console.error('캐시 데이터 변환 실패:', conversionError)
          }
        }
      }

      if (cachedData && cachedData.length > 0) {
        console.log(`전체 날씨 이미지 캐시 사용 (타입: ${type})`)
        return cachedData
      }
    }

    console.log(`전체 날씨 이미지 생성 (타입: ${type})`)

    var { value: weatherPoints } = (await cacheService.getFromCache(`weather-points`, {})) || {}

    if (!weatherPoints || weatherPoints.length === 0) {
      const weatherData = await getGlobalWeatherData(10)

      const flattenedWeatherPoints = weatherData.reduce((acc, area) => {
        return acc.concat(area.weatherPoints)
      }, [])

      weatherPoints = flattenedWeatherPoints.map(point => {
        let value
        switch (type) {
          case 'temperature':
            value = point.temperature?.current
            break
          case 'humidity':
            value = point.humidity
            break
          case 'wind':
            value = point.wind?.speed
            break
          case 'precipitation':
            value = 0
            break // 현재 데이터 없음
        }

        return {
          lat: point.location.latitude,
          lng: point.location.longitude,
          value,
          // value: point.temperature?.current,
          description: point.weatherDescription,
          temperature: point.temperature?.current,
          humidity: point.humidity,
          cloudCoverage: point.cloudCoverage,
          solarRadiation: point.solarRadiation,
          windSpeed: point.wind?.speed,
          windDirection: point.wind?.direction
          // precipitation: point.precipitation.current
        }
      })

      await cacheService.setInCache(`weather-points`, {}, weatherPoints, cacheLifetime * 60)
    }

    // Headless Chrome으로 이미지 생성
    const imageBuffer = await renderWeatherMap(type, weatherPoints, 1800, 900)

    // 캐시에 저장 (초 단위로 TTL 설정)
    await cacheService.setInCache(`global-weather-image`, { type }, imageBuffer, cacheLifetime * 60)

    return imageBuffer
  } catch (error) {
    console.error(`전체 날씨 이미지 생성 실패 (타입: ${type}):`, error)

    // 에러 발생 시 캐시에서 데이터 확인
    const { value: cachedDataJson } = (await cacheService.getFromCache(`global-weather-image`, { type })) || {}

    // Buffer.from이 객체를 직접 처리할 수 없으므로 타입에 따라 적절하게 처리
    let cachedData = null
    if (cachedDataJson) {
      if (Buffer.isBuffer(cachedDataJson)) {
        cachedData = cachedDataJson
      } else if (typeof cachedDataJson === 'string') {
        // 문자열이면 버퍼로 변환
        cachedData = Buffer.from(cachedDataJson)
      } else if (Array.isArray(cachedDataJson)) {
        // 배열이면 버퍼로 변환
        cachedData = Buffer.from(cachedDataJson)
      } else if (typeof cachedDataJson === 'object') {
        // 객체인 경우 처리 (JSON.stringify된 버퍼일 수 있음)
        try {
          // JSON 문자열로 변환했다가 다시 파싱하면 배열로 변환될 수 있음
          const dataArray = Object.keys(cachedDataJson)
            .filter(key => !isNaN(Number(key)))
            .sort((a, b) => Number(a) - Number(b))
            .map(key => cachedDataJson[key])

          if (dataArray.length > 0) {
            cachedData = Buffer.from(dataArray)
          }
        } catch (conversionError) {
          console.error('캐시 데이터 변환 실패:', conversionError)
        }
      }
    }

    if (cachedData) {
      console.log(`에러로 인해 캐시된 날씨 이미지 사용 (타입: ${type})`)
      return cachedData
    }

    throw error
  }
}
