import React from 'react';
import {Box, Text, render} from 'ink';
import chalk from 'chalk';
import axios from 'axios';
import fs from 'fs';
import path from 'path';
import os from 'os';

// React component for Current Bundle IDs table
function CurrentBundleTable({manifest}: {manifest: any}) {
	return (
		<Box flexDirection="column" marginTop={1}>
			<Text color="blue">Current Bundle IDs:</Text>
			<Box flexDirection="column" borderStyle="single" borderColor="gray">
				<Box>
					<Text>Bundle Type         </Text>
					<Text>│ ID           </Text>
				</Box>
				<Box>
					<Text>─────────────────────</Text>
					<Text>┼──────────────</Text>
				</Box>
				<Box>
					<Text>iOS Bundle ID       </Text>
					<Text>│ {(manifest.iosBundleId || 'null').toString().padEnd(12)} </Text>
				</Box>
				<Box>
					<Text>Android Bundle ID   </Text>
					<Text>│ {(manifest.androidBundleId || 'null').toString().padEnd(12)} </Text>
				</Box>
				<Box>
					<Text>Plugins Bundle ID   </Text>
					<Text>│ {(manifest.pluginsBundleId || 'null').toString().padEnd(12)} </Text>
				</Box>
				<Box>
					<Text>Navigators Bundle ID</Text>
					<Text>│ {(manifest.navigatorsBundleId || 'null').toString().padEnd(12)} </Text>
				</Box>
			</Box>
		</Box>
	);
}

// React component for Available Bundles table
function AvailableBundlesTable({bundleType, bundles}: {bundleType: string, bundles: any[]}) {
	return (
		<Box flexDirection="column" marginTop={1}>
			<Text color="blue">Available {bundleType} bundles:</Text>
			<Box flexDirection="column" borderStyle="single" borderColor="gray">
				<Box>
					<Text>ID       </Text>
					<Text>│ Type                </Text>
				</Box>
				<Box>
					<Text>──────────</Text>
					<Text>┼─────────────────────</Text>
				</Box>
				{bundles.map((bundle, index) => {
					const id = bundle.id !== null ? bundle.id.toString() : 'null';
					return (
						<Box key={index}>
							<Text>{id.padEnd(8)} </Text>
							<Text>│ {bundle.type.padEnd(19)} </Text>
						</Box>
					);
				})}
			</Box>
		</Box>
	);
}

function serializeAxiosError(err: any) {
	if (err && err.response && err.code) {
		let errorBody = err.response.data;
		if (typeof errorBody === "object") {
			errorBody = JSON.stringify(err.response.data);
		}
		let serialized = `calling: ${err.request.protocol}//${err.request.host}${err.request.path}
${chalk.red(err.code)}
${chalk.yellow(err.response.status)} ${chalk.yellow(err.response.statusText)}`;

		if (errorBody) {
			serialized += `\n\n${errorBody}`
		}

		return serialized;
	} else {
		return null;
	}
}

async function getUser() {
	try {
		const homeDir = os.homedir();
		const apptileCliDir = path.join(homeDir, '.apptile-cli');
		const stateFilePath = path.join(apptileCliDir, 'apptile-cli-state.json');
		
		const rawdata = fs.readFileSync(stateFilePath, { encoding: "utf8" });
		const parsed = JSON.parse(rawdata);
		const { status, data } = await axios.get("https://api.apptile.io/api/users/me", {
			headers: {
				cookie: parsed.cookie
			}
		});
		if (status === 200) {
			return { user: data, cookie: parsed.cookie };
		} else {
			return { user: null, cookie: "" };
		}
	} catch (err) {
		const msg = serializeAxiosError(err);
		if (msg) {
			console.log(msg);
		} else {
			console.log(err);
		}
		return { user: null, cookie: "" };
	}
}

async function getManifest(appId: string) {
	try {
		const { data } = await axios.get(`https://api.apptile.io/api/v2/app/${appId}/manifest`);
		return data;
	} catch (err) {
		const msg = serializeAxiosError(err);
		if (msg) {
			console.log(msg);
		}
		return null;
	}
}

// Main React component for CodePush functionality
function CodePushApp({options}: {options: any}) {
	const [config, setConfig] = React.useState<any>(null);
	const [manifest, setManifest] = React.useState<any>(null);
	const [bundles, setBundles] = React.useState<any[]>([]);
	const [error, setError] = React.useState<string>('');
	const [loading, setLoading] = React.useState<boolean>(true);

	React.useEffect(() => {
		async function loadData() {
			try {
				// Check if apptile.config.json exists in current directory
				const configPath = path.resolve(process.cwd(), "apptile.config.json");
				if (!fs.existsSync(configPath)) {
					setError("Error: apptile.config.json not found in current directory.\nPlease run this command from the root of your apptile project.");
					setLoading(false);
					return;
				}

				// Read apptile.config.json
				let configData;
				try {
					const configRaw = fs.readFileSync(configPath, { encoding: "utf8" });
					configData = JSON.parse(configRaw);
				} catch (err: any) {
					setError(`Error: Could not read or parse apptile.config.json\n${err.message}`);
					setLoading(false);
					return;
				}

				if (!configData.APP_ID) {
					setError("Error: APP_ID not found in apptile.config.json");
					setLoading(false);
					return;
				}

				if (!configData.APPTILE_BACKEND_URL) {
					setError("Error: APPTILE_BACKEND_URL not found in apptile.config.json");
					setLoading(false);
					return;
				}

				setConfig(configData);

				// If showing current bundle IDs, fetch the manifest
				if (options.showCurrent) {
					try {
						const manifestData = await getManifest(configData.APP_ID);
						if (!manifestData) {
							setError("Error: Could not fetch app manifest");
							setLoading(false);
							return;
						}
						setManifest(manifestData);
					} catch (err: any) {
						setError(`Error fetching manifest: ${err.message}`);
						setLoading(false);
						return;
					}
				}

				// If listing available bundles, fetch them
				if (options.listAvailableBundles) {
					const bundleType = options.listAvailableBundles.toLowerCase();
					const validTypes = ['plugins', 'ios', 'navigators', 'android'];
					
					if (!validTypes.includes(bundleType)) {
						setError(`Error: Invalid bundle type '${bundleType}'. Valid types are: ${validTypes.join(', ')}`);
						setLoading(false);
						return;
					}

					try {
						// Get user authentication
						const { cookie } = await getUser();
						if (!cookie) {
							setError("Not logged in! Please run 'aptl login' first.");
							setLoading(false);
							return;
						}

						// Call the API to get bundles
						const apiUrl = `${configData.APPTILE_BACKEND_URL}/api/v2/app/${configData.APP_ID}/bundles`;
						const { data } = await axios.get(apiUrl, {
							headers: {
								cookie: cookie
							}
						});

						// Filter bundles by type
						const typeMapping: { [key: string]: string } = {
							'ios': 'ios-jsbundle',
							'android': 'android-jsbundle',
							'plugins': 'plugins',
							'navigators': 'navigators'
						};

						const apiType = typeMapping[bundleType];
						const filteredBundles = data.filter((bundle: any) => bundle.type === apiType);

						setBundles(filteredBundles);

					} catch (err: any) {
						const msg = serializeAxiosError(err);
						if (msg) {
							setError(msg);
						} else {
							setError(`Error fetching bundles: ${err.message}`);
						}
						setLoading(false);
						return;
					}
				}

				setLoading(false);

			} catch (err: any) {
				setError(`Error: ${err.message}`);
				setLoading(false);
			}
		}

		loadData();
	}, [options]);

	if (loading) {
		return <Text>Loading...</Text>;
	}

	if (error) {
		return <Text color="red">{error}</Text>;
	}

	if (options.showCurrent && manifest) {
		return <CurrentBundleTable manifest={manifest} />;
	}

	if (options.listAvailableBundles && config) {
		const bundleType = options.listAvailableBundles.toLowerCase();
		
		if (bundles.length === 0) {
			return <Text color="yellow">No {bundleType} bundles found.</Text>;
		}

		return <AvailableBundlesTable bundleType={bundleType} bundles={bundles} />;
	}

	// If no options provided, show help
	return (
		<Box flexDirection="column">
			<Text color="yellow">Please specify an option:</Text>
			<Text>  --show-current                           Show current bundle IDs</Text>
			<Text>  --list-available-bundles &lt;type&gt;          List available bundles</Text>
			<Text>                                           Types: plugins, ios, navigators, android</Text>
			<Text></Text>
			<Text>Examples:</Text>
			<Text>  aptl codepush --show-current</Text>
			<Text>  aptl codepush --list-available-bundles=plugins</Text>
		</Box>
	);
}

export async function codepushAction(options: any) {
	// Render the React component using Ink
	render(<CodePushApp options={options} />);
}
