import { OpenAPIHono } from '@hono/zod-openapi';
import type { BlankEnv } from 'hono/types';
import { cors } from 'hono/cors';
import type { ProviderId, AuthInfo } from '@ottocode/sdk';
import { TerminalManager } from '@ottocode/sdk';
import { setTerminalManager } from '@ottocode/sdk';
import { registerRootRoutes } from './routes/root.ts';
import { registerOpenApiRoute } from './routes/openapi.ts';
import { registerSessionsRoutes } from './routes/sessions.ts';
import { registerSessionMessagesRoutes } from './routes/session-messages.ts';
import { registerSessionStreamRoute } from './routes/session-stream.ts';
import { registerClientEventsRoute } from './routes/client-events.ts';
import { registerAskRoutes } from './routes/ask.ts';
import { registerConfigRoutes } from './routes/config/index.ts';
import { registerFilesRoutes } from './routes/files.ts';
import { registerGitRoutes } from './routes/git/index.ts';
import { registerTerminalsRoutes } from './routes/terminals.ts';
import { registerSessionFilesRoutes } from './routes/session-files.ts';
import { registerBranchRoutes } from './routes/branch.ts';
import { registerResearchRoutes } from './routes/research.ts';
import { registerGoalsRoutes } from './routes/goals.ts';
import { registerSubagentsRoutes } from './routes/subagents.ts';
import { registerSessionApprovalRoute } from './routes/session-approval.ts';
import { registerSessionSecureInputRoute } from './routes/session-secure-input.ts';
import { registerOttoRouterRoutes } from './routes/ottorouter.ts';
import { registerAuthRoutes } from './routes/auth.ts';
import { registerTunnelRoutes } from './routes/tunnel.ts';
import { registerMCPRoutes } from './routes/mcp.ts';
import { registerProviderUsageRoutes } from './routes/provider-usage.ts';
import { registerDoctorRoutes } from './routes/doctor.ts';
import { registerSkillsRoutes } from './routes/skills.ts';
import { registerUsageRoutes } from './routes/usage.ts';
import { registerAttachmentRoutes } from './routes/attachments.ts';
import { registerSimulatorRoutes } from './routes/simulator.ts';
import { registerDictationRoutes } from './routes/dictation.ts';
import type {
	AgentConfigEntry,
	AgentToolConfig,
} from './runtime/agent/registry.ts';
import { installAiSdkWarningHandler } from './runtime/ai-sdk-warnings.ts';

const globalTerminalManager = new TerminalManager();
setTerminalManager(globalTerminalManager);

// Suppress noisy AI SDK provider warnings unless debug mode is enabled.
installAiSdkWarningHandler();

const corsAllowHeaders = [
	'Content-Type',
	'Authorization',
	'X-Requested-With',
	'Access-Control-Request-Private-Network',
];

function applyPrivateNetworkAccessHeaders(app: OpenAPIHono<BlankEnv>) {
	app.use('*', async (c, next) => {
		c.header('Access-Control-Allow-Private-Network', 'true');
		await next();
	});
}

function initApp() {
	const app = new OpenAPIHono<BlankEnv>();
	applyPrivateNetworkAccessHeaders(app);

	// Enable CORS for localhost and local network access
	app.use(
		'*',
		cors({
			origin: (origin) => {
				// Allow all localhost and 127.0.0.1 on any port
				if (
					origin.startsWith('http://localhost:') ||
					origin.startsWith('http://127.0.0.1:') ||
					origin.startsWith('https://localhost:') ||
					origin.startsWith('https://127.0.0.1:')
				) {
					return origin;
				}
				// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
				const localNetworkPattern =
					/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
				if (localNetworkPattern.test(origin)) {
					return origin;
				}
				// Default to allowing the origin (can be restricted in production)
				return origin;
			},
			allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
			allowHeaders: corsAllowHeaders,
			exposeHeaders: ['Content-Length', 'X-Request-Id'],
			credentials: true,
			maxAge: 600,
		}),
	);

	registerRootRoutes(app);
	registerOpenApiRoute(app);
	registerSessionsRoutes(app);
	registerSessionApprovalRoute(app);
	registerSessionSecureInputRoute(app);
	registerSessionMessagesRoutes(app);
	registerSessionStreamRoute(app);
	registerClientEventsRoute(app);
	registerAskRoutes(app);
	registerConfigRoutes(app);
	registerFilesRoutes(app);
	registerGitRoutes(app);
	registerTerminalsRoutes(app, globalTerminalManager);
	registerSessionFilesRoutes(app);
	registerBranchRoutes(app);
	registerResearchRoutes(app);
	registerGoalsRoutes(app);
	registerSubagentsRoutes(app);
	registerOttoRouterRoutes(app);
	registerAuthRoutes(app);
	registerTunnelRoutes(app);
	registerMCPRoutes(app);
	registerProviderUsageRoutes(app);
	registerDoctorRoutes(app);
	registerSkillsRoutes(app);
	registerUsageRoutes(app);
	registerAttachmentRoutes(app);
	registerSimulatorRoutes(app);
	registerDictationRoutes(app);

	return app;
}

const app = initApp();

export default {
	port: 0,
	fetch: app.fetch,
};

export function createApp() {
	return app;
}

export type StandaloneAppConfig = {
	provider?: ProviderId;
	model?: string;
	defaultAgent?: string;
};

export function createStandaloneApp(_config?: StandaloneAppConfig) {
	const honoApp = new OpenAPIHono<BlankEnv>();
	applyPrivateNetworkAccessHeaders(honoApp);

	honoApp.use(
		'*',
		cors({
			origin: (origin) => {
				// Allow all localhost and 127.0.0.1 on any port
				if (
					origin.startsWith('http://localhost:') ||
					origin.startsWith('http://127.0.0.1:') ||
					origin.startsWith('https://localhost:') ||
					origin.startsWith('https://127.0.0.1:')
				) {
					return origin;
				}
				// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
				const localNetworkPattern =
					/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
				if (localNetworkPattern.test(origin)) {
					return origin;
				}
				// Default to allowing the origin
				return origin;
			},
			allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
			allowHeaders: corsAllowHeaders,
			exposeHeaders: ['Content-Length', 'X-Request-Id'],
			credentials: true,
			maxAge: 600,
		}),
	);

	registerRootRoutes(honoApp);
	registerOpenApiRoute(honoApp);
	registerSessionsRoutes(honoApp);
	registerSessionApprovalRoute(honoApp);
	registerSessionSecureInputRoute(honoApp);
	registerSessionMessagesRoutes(honoApp);
	registerSessionStreamRoute(honoApp);
	registerClientEventsRoute(honoApp);
	registerAskRoutes(honoApp);
	registerConfigRoutes(honoApp);
	registerFilesRoutes(honoApp);
	registerGitRoutes(honoApp);
	registerTerminalsRoutes(honoApp, globalTerminalManager);
	registerSessionFilesRoutes(honoApp);
	registerBranchRoutes(honoApp);
	registerResearchRoutes(honoApp);
	registerOttoRouterRoutes(honoApp);
	registerAuthRoutes(honoApp);
	registerTunnelRoutes(honoApp);
	registerMCPRoutes(honoApp);
	registerProviderUsageRoutes(honoApp);
	registerUsageRoutes(honoApp);
	registerAttachmentRoutes(honoApp);
	registerSimulatorRoutes(honoApp);
	registerDictationRoutes(honoApp);

	return honoApp;
}

/**
 * Embedded app configuration with hybrid fallback:
 * 1. Injected config (highest priority)
 * 2. Environment variables
 * 3. auth.json/config.json files (fallback)
 *
 * All fields are optional - if not provided, falls back to files/env
 */
export type EmbeddedAppConfig = {
	/** Primary provider (optional - falls back to config.json or env) */
	provider?: ProviderId;
	/** Primary model (optional - falls back to config.json) */
	model?: string;
	/** Primary API key (optional - falls back to env vars or auth.json) */
	apiKey?: string;
	/** Default agent (optional - falls back to config.json) */
	agent?: string;
	/** Multi-provider auth (optional - falls back to auth.json) */
	auth?: Record<string, { apiKey: string } | AuthInfo>;
	/** Custom agents (optional - falls back to .otto/agents/) */
	agents?: Record<
		string,
		Omit<AgentConfigEntry, 'tools'> & { tools?: AgentToolConfig }
	>;
	/** Default settings (optional - falls back to config.json) */
	defaults?: {
		provider?: ProviderId;
		model?: string;
		agent?: string;
		toolApproval?: 'auto' | 'dangerous' | 'all' | 'yolo';
		theme?: 'light' | 'dark';
		vimMode?: boolean;
		compactThread?: boolean;
		fontFamily?: string;
		smartEdges?: boolean;
		releaseToSend?: boolean;
		fullWidthContent?: boolean;
		autoCompactThresholdTokens?: number | null;
		ottoEnabled?: boolean;
	};
	/** Additional CORS origins for proxies/Tailscale (e.g., ['https://myapp.ts.net', 'https://example.com']) */
	corsOrigins?: string[];
};

export function createEmbeddedApp(config: EmbeddedAppConfig = {}) {
	const honoApp = new OpenAPIHono<BlankEnv>();
	applyPrivateNetworkAccessHeaders(honoApp);

	// Store injected config in Hono context for routes to access
	// Config can be empty - routes will fall back to files/env
	honoApp.use('*', async (c, next) => {
		(
			c as unknown as {
				set: (
					key: 'embeddedConfig',
					value: EmbeddedAppConfig | undefined,
				) => void;
			}
		).set('embeddedConfig', config);
		await next();
	});

	honoApp.use(
		'*',
		cors({
			origin: (origin) => {
				// Allow all localhost and 127.0.0.1 on any port
				if (
					origin.startsWith('http://localhost:') ||
					origin.startsWith('http://127.0.0.1:') ||
					origin.startsWith('https://localhost:') ||
					origin.startsWith('https://127.0.0.1:')
				) {
					return origin;
				}
				// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
				const localNetworkPattern =
					/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
				if (localNetworkPattern.test(origin)) {
					return origin;
				}
				// Allow custom CORS origins (for Tailscale, proxies, etc.)
				if (config.corsOrigins?.includes(origin)) {
					return origin;
				}
				// Default to allowing the origin
				return origin;
			},
			allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
			allowHeaders: corsAllowHeaders,
			exposeHeaders: ['Content-Length', 'X-Request-Id'],
			credentials: true,
			maxAge: 600,
		}),
	);

	registerRootRoutes(honoApp);
	registerOpenApiRoute(honoApp);
	registerSessionsRoutes(honoApp);
	registerSessionApprovalRoute(honoApp);
	registerSessionSecureInputRoute(honoApp);
	registerSessionMessagesRoutes(honoApp);
	registerSessionStreamRoute(honoApp);
	registerClientEventsRoute(honoApp);
	registerAskRoutes(honoApp);
	registerConfigRoutes(honoApp);
	registerFilesRoutes(honoApp);
	registerGitRoutes(honoApp);
	registerTerminalsRoutes(honoApp, globalTerminalManager);
	registerSessionFilesRoutes(honoApp);
	registerBranchRoutes(honoApp);
	registerResearchRoutes(honoApp);
	registerOttoRouterRoutes(honoApp);
	registerAuthRoutes(honoApp);
	registerTunnelRoutes(honoApp);
	registerMCPRoutes(honoApp);
	registerProviderUsageRoutes(honoApp);
	registerUsageRoutes(honoApp);
	registerAttachmentRoutes(honoApp);
	registerSimulatorRoutes(honoApp);
	registerDictationRoutes(honoApp);

	return honoApp;
}

export {
	resolveAgentConfig,
	defaultToolConfigForAgent,
	flattenAgentToolConfig,
	BUILTIN_AGENT_NAMES,
	HIDDEN_BUILTIN_AGENT_NAMES,
	isHiddenAgent,
	type AgentToolConfig,
	type AgentToolGroups,
} from './runtime/agent/registry.ts';
export {
	getAgentDetail,
	getAllAgentDetails,
	upsertAgentConfig,
	deleteAgentConfig,
	validateAgentName,
	type AgentDetail,
	type AgentConfigScope,
} from './runtime/agent/config-management.ts';
export {
	composeSystemPrompt,
	type ComposedSystemPrompt,
} from './runtime/prompt/builder.ts';
export {
	buildCapabilitySummary,
	type CapabilitySummaryResult,
	type CapabilitySummaryMCPTool,
} from './runtime/prompt/capabilities.ts';
export {
	AskServiceError,
	handleAskRequest,
	deriveStatusFromMessage,
	inferStatus,
} from './runtime/ask/service.ts';
export { registerSessionsRoutes } from './routes/sessions.ts';
export { registerAskRoutes } from './routes/ask.ts';
export {
	BUILTIN_AGENTS,
	BUILTIN_TOOLS,
	type BuiltinAgent,
	type BuiltinTool,
} from './presets.ts';

// Export debug state management
export {
	setDebugEnabled,
	isDebugEnabled,
	setTraceEnabled,
	isTraceEnabled,
} from './runtime/debug/state.ts';
export { logger } from '@ottocode/sdk';

// Export server state management
export { setServerPort, getServerPort, getServerInfo } from './state.ts';

// Export WebSocket handler for Bun.serve()
export { websocket as bunWebSocket } from './ws.ts';
