import { describe, it, expect, beforeEach, afterEach } from "bun:test"
import { promises as fs } from "node:fs"
import path from "node:path"
import { generateNextApp } from "../../generate-next"
import { generateReactApp } from "../../generate-react"
import type { Chain } from "../../types"

const TEST_DIR = path.join(process.cwd(), "test-output")
let testFailed = false

describe("App Generation", () => {
	const mockChains: Chain[] = [
		{
			name: "Ethereum",
			package: "@dynamic-labs/ethereum",
			connector: "EthereumWalletConnectors",
		},
		{
			name: "Solana",
			package: "@dynamic-labs/solana",
			connector: "SolanaWalletConnectors",
		},
	]

	beforeEach(async () => {
		testFailed = false
		// Clean up any existing test directory
		try {
			await fs.rm(TEST_DIR, { recursive: true, force: true })
		} catch {
			// Ignore errors during cleanup
		}
		await fs.mkdir(TEST_DIR, { recursive: true })
	})

	afterEach(async () => {
		// Only cleanup if test passed
		if (testFailed) {
			console.log(`Test failed - keeping directory ${TEST_DIR} for inspection`)
			return
		}
		try {
			await fs.rm(TEST_DIR, { recursive: true, force: true })
		} catch {
			// Ignore errors during cleanup
		}
	})

	it("should generate a Next.js app with Ethereum and viem", async () => {
		try {
			const appName = "test-next-app"
			const appDir = path.join(TEST_DIR, appName)

			await generateNextApp(TEST_DIR, appName, true, false, [mockChains[0]])

			// Check if directories exist
			expect(await fs.stat(appDir)).toBeTruthy()
			expect(await fs.stat(path.join(appDir, "app"))).toBeTruthy()
			expect(await fs.stat(path.join(appDir, "app/components"))).toBeTruthy()
			expect(await fs.stat(path.join(appDir, "lib"))).toBeTruthy()

			// Check if files exist
			const files = [
				"app/layout.tsx",
				"app/page.tsx",
				"app/page.css",
				"app/components/Methods.tsx",
				"app/components/Methods.css",
				"lib/providers.tsx",
				"lib/useDarkMode.ts",
				"lib/dynamic.ts",
				"package.json",
			]

			for (const file of files) {
				expect(await fs.stat(path.join(appDir, file))).toBeTruthy()
			}

			// Check package.json content
			const packageJson = JSON.parse(
				await fs.readFile(path.join(appDir, "package.json"), "utf8")
			)
			expect(packageJson.dependencies["@dynamic-labs/ethereum"]).toBeTruthy()
			expect(packageJson.dependencies["viem"]).toBeTruthy()
		} catch (error) {
			testFailed = true
			throw error
		}
	}, 60000) // 60 second timeout

	it("should generate a React app with Solana", async () => {
		try {
			const appName = "test-react-app"
			const appDir = path.join(TEST_DIR, appName)

			await generateReactApp(TEST_DIR, appName, false, false, [mockChains[1]])

			// Check if directories exist
			expect(await fs.stat(appDir)).toBeTruthy()
			expect(await fs.stat(path.join(appDir, "src"))).toBeTruthy()
			expect(await fs.stat(path.join(appDir, "src/components"))).toBeTruthy()

			// Check if files exist
			const files = [
				"src/App.tsx",
				"src/App.css",
				"src/main.tsx",
				"src/index.css",
				"src/components/Methods.tsx",
				"src/components/Methods.css",
				"package.json",
				"index.html",
				"vite.config.ts",
			]

			for (const file of files) {
				expect(await fs.stat(path.join(appDir, file))).toBeTruthy()
			}

			// Check package.json content
			const packageJson = JSON.parse(
				await fs.readFile(path.join(appDir, "package.json"), "utf8")
			)
			expect(packageJson.dependencies["@dynamic-labs/solana"]).toBeTruthy()

			// Check vite.config.ts for Solana polyfills
			const viteConfig = await fs.readFile(
				path.join(appDir, "vite.config.ts"),
				"utf8"
			)
			expect(viteConfig).toContain("nodePolyfills")
			expect(viteConfig).toContain("Buffer: true")
			expect(viteConfig).toContain("process: true")
		} catch (error) {
			testFailed = true
			throw error
		}
	}, 60000) // 60 second timeout
})
