import { getCreateMigrationsTableSQL, getInsertMigrationSQL } from '@supabase/pg-meta'

import { isResponseOk } from './api/apiWrapper'
import { fetchHandler } from '@/data/fetchers'
import type { Integration } from '@/data/integrations/integrations.types'
import { ResponseError, type SupaResponse } from '@/types'

async function fetchGitHub<T = any>(url: string, responseJson = true): Promise<SupaResponse<T>> {
  const response = await fetchHandler(url)
  if (!response.ok) {
    return {
      error: new ResponseError(response.statusText, response.status),
    }
  }
  try {
    return (responseJson ? await response.json() : await response.text()) as T
  } catch (error: any) {
    return {
      error: new ResponseError(error.message, 500),
    }
  }
}

export type File = {
  name: string
  download_url: string
}

/**
 * Returns the initial migration SQL from a GitHub repo.
 * @param externalId An external GitHub URL for example: https://github.com/vercel/next.js/tree/canary/examples/with-briven
 */
export async function getInitialMigrationSQLFromGitHubRepo(
  externalId?: string
): Promise<string | null> {
  if (!externalId) return null

  const [, , , owner, repo, , branch, ...pathSegments] = externalId?.split('/') ?? []
  const path = pathSegments.join('/')

  const baseGitHubUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${path}`
  const brivenFolderUrl = `${baseGitHubUrl}/briven?ref=${branch}`
  const brivenMigrationsPath = `briven/migrations` // TODO: read this from the `briven/config.toml` file
  const migrationsFolderUrl = `${baseGitHubUrl}/${brivenMigrationsPath}${
    branch ? `?ref=${branch}` : ``
  }`

  const [brivenFilesResponse, migrationFilesResponse] = await Promise.all([
    fetchGitHub<File[]>(brivenFolderUrl),
    fetchGitHub<File[]>(migrationsFolderUrl),
  ])

  if (!isResponseOk(brivenFilesResponse)) {
    console.warn(`Failed to fetch briven files from GitHub: ${brivenFilesResponse.error}`)
    return null
  }
  if (!isResponseOk(migrationFilesResponse)) {
    console.warn(`Failed to fetch migration files from GitHub: ${migrationFilesResponse.error}`)
    return null
  }

  const seedFileUrl = brivenFilesResponse.find((file) => file.name === 'seed.sql')?.download_url
  const sortedFiles = migrationFilesResponse.sort((a, b) => {
    // sort by name ascending
    if (a.name < b.name) return -1
    if (a.name > b.name) return 1
    return 0
  })
  const migrationFileDownloadUrlPromises = sortedFiles.map((file) =>
    fetchGitHub<string>(file.download_url, false)
  )

  const [seedFileResponse, ...migrationFileResponses] = await Promise.all([
    seedFileUrl ? fetchGitHub<string>(seedFileUrl, false) : Promise.resolve<string>(''),
    ...migrationFileDownloadUrlPromises,
  ])

  const migrations = migrationFileResponses.filter((response) => isResponseOk(response)).join(';')
  const seed = isResponseOk(seedFileResponse) ? seedFileResponse : ''

  const createMigrationsTableSql = getCreateMigrationsTableSQL()

  const migrationsTableSql = `
    ${createMigrationsTableSql}
    ${sortedFiles
      .map((file, i) => {
        const migration = migrationFileResponses[i]
        if (!isResponseOk(migration)) return ''

        const version = file.name.split('_')[0]
        const statements = JSON.stringify(
          migration
            .split(';')
            .map((statement) => statement.trim())
            .filter(Boolean)
        )
        return getInsertMigrationSQL({ name: file.name, version, statements })
      })
      .join('')}
  `

  return `${migrations};${migrationsTableSql};${seed}`
}

type VercelIntegration = Extract<Integration, { integration: { name: 'Vercel' } }>
type GitHubIntegration = Extract<Integration, { integration: { name: 'GitHub' } }>

export function getIntegrationConfigurationUrl(integration: Integration) {
  if (integration.integration.name === 'Vercel') {
    return getVercelConfigurationUrl(integration as VercelIntegration)
  }

  if (integration.integration.name === 'GitHub') {
    return getGitHubConfigurationUrl(integration as GitHubIntegration)
  }

  return ''
}

function getVercelConfigurationUrl(integration: VercelIntegration) {
  return `https://vercel.com/dashboard/${
    integration.metadata?.account.type === 'Team'
      ? `${integration.metadata?.account.team_slug}/`
      : ''
  }integrations/${integration.metadata?.configuration_id}`
}

function getGitHubConfigurationUrl(integration: GitHubIntegration) {
  return `https://github.com/${
    integration.metadata?.account.type === 'Organization'
      ? `organizations/${integration.metadata?.account.name}/`
      : ''
  }settings/installations/${integration.metadata?.installation_id}`
}
