import { BASE_CHAIN_ID, URL_API_KEY_PROD } from "@/constants"
import {
  getBaseBackendUrl,
  getMorphoYieldExecutorId,
} from "../morphoStrategy/utils"
import { Address, TokenPrice } from "./types"
import {
  MorphoVault,
  MorphoYieldAutomation,
  MorphoYieldAutomationLogResponse,
  MorphoYieldVaultPosition,
} from "../morphoStrategy/types"
import { SupportedChainIds } from "@/types"

import { Alchemy, Network } from "alchemy-sdk"

const config = {
  apiKey: process.env.NEXT_PUBLIC_ALCHEMY_API,
  network: Network.BASE_MAINNET,
}
const alchemy = new Alchemy(config)

export const callIndexer = async (txnHash: string) => {
  try {
    await fetch(`${getBaseBackendUrl()}/indexer/process/${txnHash}/8453`, {
      method: "POST",
      headers: {
        "x-api-key": URL_API_KEY_PROD,
      },
    })
  } catch (err) {
    console.error("[error at fetchMorphoYieldAutomation]", err)
  }
}

export const fetchMorphoYieldAutomation = async (
  consoleAddress: Address,
  chainId: SupportedChainIds,
): Promise<MorphoYieldAutomation[]> => {
  try {
    const response = await fetch(
      `${getBaseBackendUrl()}/automations/subscriptions/console/${consoleAddress}/${chainId}`,
      {
        headers: {
          "x-api-key": URL_API_KEY_PROD,
        },
      },
    )

    const jsonResponse = await response.json()
    return jsonResponse.data
  } catch (err) {
    console.error("[error at fetchMorphoYieldAutomation]", err)
    return []
  }
}

export const fetchAutomationsFromEoa = async (
  eoa: Address,
): Promise<MorphoYieldAutomation[]> => {
  try {
    const response = await fetch(
      `${getBaseBackendUrl()}/automations/subscriptions/owner/${eoa}/${getMorphoYieldExecutorId(
        8453,
      )}`,
      {
        headers: {
          "x-api-key": URL_API_KEY_PROD,
        },
      },
    )

    const jsonResponse = await response.json()
    return jsonResponse.data
  } catch (err) {
    console.error("[error at fetchAutomationConsoleAddress]", err)
    return []
  }
}

export const fetchMorphoYieldLogs = async (
  id: string,
): Promise<MorphoYieldAutomationLogResponse[]> => {
  try {
    const response = await fetch(`${getBaseBackendUrl()}/kernel/logs/${id}`, {
      headers: {
        "x-api-key": URL_API_KEY_PROD,
      },
    })

    const jsonResponse = await response.json()
    return jsonResponse.data
  } catch (err) {
    console.error("[error at fetchMorphoYieldLogs]", err)
    return []
  }
}

export const fetchMorphoYieldVaultPosition = async (
  subaccountAddress: Address,
): Promise<MorphoYieldVaultPosition[]> => {
  try {
    const response = await fetch(
      `${getBaseBackendUrl()}/builder/morpho/user/${subaccountAddress}`,
      {
        headers: {
          "x-api-key": URL_API_KEY_PROD,
        },
      },
    )

    const jsonResponse = await response.json()
    return jsonResponse.data
  } catch (err) {
    console.error("[error at fetchMorphoYieldVaultPosition]", err)
    return []
  }
}

export const fetchMorphoYieldVaults = async (): Promise<MorphoVault[]> => {
  try {
    const response = await fetch(
      `${getBaseBackendUrl()}/builder/morpho/vaults`,
      {
        headers: {
          "x-api-key": URL_API_KEY_PROD,
        },
      },
    )

    const jsonResponse = await response.json()
    return jsonResponse.data
  } catch (err) {
    console.error("[error at fetchMorphoYieldVaults]", err)
    return []
  }
}

export const clearChatSession = async (userEoa: Address): Promise<void> => {
  try {
    await fetch(`${getBaseBackendUrl()}/prompter/clear?session_id=${userEoa}`, {
      method: "POST",
      headers: {
        "x-api-key": URL_API_KEY_PROD,
      },
    })
  } catch (err) {
    console.error("[error at fetchMorphoYieldVaults]", err)
  }
}

export const withdrawMorphoAmount = async ({
  consoleAddress,
  subaccountAddress,
  eoa,
  vaultAddress,
  baseAsset,
}: {
  subaccountAddress: Address
  consoleAddress: Address
  eoa: Address
  vaultAddress: string | null
  baseAsset: Address
}) => {
  try {
    const withdrawParams = {
      id: "MORPHO",
      action: "CANCEL",
      params: {
        chainId: BASE_CHAIN_ID,
        subAccountAddress: subaccountAddress,
        data: {
          ownerSafe: consoleAddress,
          ownerEOA: eoa,
          vault: vaultAddress,
          baseAsset,
        },
      },
    }

    const payload = JSON.stringify(withdrawParams)
    console.log({ payload })

    const generateTxnResponse = await fetch(
      `${getBaseBackendUrl()}/builder/generate`,
      {
        method: "POST",
        body: payload,
        headers: {
          "x-api-key": URL_API_KEY_PROD,
          "Content-Type": "application/json",
        },
      },
    )

    const txnResponse = await generateTxnResponse.json()
    return txnResponse.data
  } catch (err) {
    console.error("[error at withdrawMorphoAmount]", err)
    return []
  }
}

export const sendUserPrompt = async (
  sessionId: Address,
  userPrompt: string,
): Promise<{ data: Response | null; error?: string } | null> => {
  try {
    const response = await fetch(
      `${getBaseBackendUrl()}/prompter/stream?session_id=${sessionId}`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Accept: "text/event-stream",
          "x-api-key": URL_API_KEY_PROD,
        },
        body: JSON.stringify({ message: userPrompt }),
      },
    )

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    return { data: response }
  } catch (err: any) {
    console.error("[error at fetchMorphoYieldVaults]", err)
    return { data: null, error: err?.message }
  }
}

export const getTokenPrice = async (
  address: Address,
  chain: string,
): Promise<{ data: number | null; error?: string }> => {
  const tokenKey = `${chain}:${address}`
  try {
    const response = await fetch(
      `https://coins.llama.fi/prices/current/${tokenKey}`,
    )

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    const jsonResponse = await response.json()
    const tokenResponse = jsonResponse.coins[tokenKey] as TokenPrice

    return { data: tokenResponse.price }
  } catch (err: any) {
    console.error("[error at getTokenPrice]", err)
    return { data: 0, error: err?.message }
  }
}

type TokenMetadata = {
  decimals: number
  logo: string
  name: string
  symbol: string
}
export const getTokenMetadata = async (
  address: Address,
): Promise<{ data: TokenMetadata | null; error?: string }> => {
  try {
    const metadata = (await alchemy.core.getTokenMetadata(
      address,
    )) as TokenMetadata

    if (!metadata) {
      throw new Error("failed to fetch")
    }
    return { data: metadata }
  } catch (err: any) {
    console.error("[error at getTokenMetadata]", err)
    return { data: null, error: err?.message }
  }
}
