import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
import { ReactWidget, Message } from '@theia/core/lib/browser';
import { WorkspaceService } from '@theia/workspace/lib/browser';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import URI from '@theia/core/lib/common/uri';
import * as React from '@theia/core/shared/react';
import '../../src/browser/style/index.css';

interface Route {
    label: string;
    path: string;
}

interface DesignPanelState {
    routes: Route[];
    selectedRoute: string | null;
    previewUrl: string;
    scanning: boolean;
}

@injectable()
export class DesignPanelWidget extends ReactWidget {

    static readonly ID = 'vibn.design.panel';
    static readonly LABEL = 'Design';

    @inject(WorkspaceService)
    protected readonly workspaceService: WorkspaceService;

    @inject(FileService)
    protected readonly fileService: FileService;

    protected state: DesignPanelState = {
        routes: [],
        selectedRoute: null,
        previewUrl: 'http://localhost:3000',
        scanning: false,
    };

    @postConstruct()
    protected init(): void {
        this.id = DesignPanelWidget.ID;
        this.title.label = DesignPanelWidget.LABEL;
        this.title.caption = 'Design — screen browser & live preview';
        this.title.iconClass = 'codicon codicon-browser';
        this.title.closable = true;
        this.node.tabIndex = 0;

        this.workspaceService.onWorkspaceChanged(() => this.scanRoutes());
        this.workspaceService.ready.then(() => this.scanRoutes());
    }

    protected override onActivateRequest(msg: Message): void {
        super.onActivateRequest(msg);
        this.node.focus();
    }

    protected setState(partial: Partial<DesignPanelState>): void {
        this.state = { ...this.state, ...partial };
        this.update();
    }

    protected async scanRoutes(): Promise<void> {
        this.setState({ scanning: true, routes: [] });

        const roots = await this.workspaceService.roots;
        if (!roots.length) {
            this.setState({ scanning: false });
            return;
        }

        const routes: Route[] = [];

        for (const root of roots) {
            const appDir = root.resource.resolve('app');
            try {
                await this.collectRoutes(appDir, '', routes);
            } catch {
                // app/ dir may not exist yet
            }
        }

        routes.sort((a, b) => a.path.localeCompare(b.path));
        this.setState({ scanning: false, routes });
    }

    protected async collectRoutes(dir: URI, routePrefix: string, result: Route[]): Promise<void> {
        let stat;
        try {
            stat = await this.fileService.resolve(dir);
        } catch {
            return;
        }

        if (!stat.isDirectory || !stat.children) {
            return;
        }

        for (const child of stat.children) {
            // Skip private folders like (auth), _components, etc.
            const name = child.name;
            if (name.startsWith('_') || name.startsWith('.')) {
                continue;
            }

            if (child.isDirectory) {
                // Route groups like (auth) — strip parens for routing, keep for display
                const isRouteGroup = name.startsWith('(') && name.endsWith(')');
                const segment = isRouteGroup ? '' : '/' + name;
                await this.collectRoutes(child.resource, routePrefix + segment, result);
            } else if (child.name === 'page.tsx' || child.name === 'page.ts' || child.name === 'page.jsx' || child.name === 'page.js') {
                const routePath = routePrefix || '/';
                result.push({
                    label: routePath,
                    path: routePath,
                });
            }
        }
    }

    protected handleRouteClick(route: Route): void {
        const base = this.state.previewUrl.replace(/\/$/, '');
        const path = route.path === '/' ? '' : route.path;
        this.setState({ selectedRoute: route.path, previewUrl: base + path });
    }

    protected handleUrlChange(e: React.ChangeEvent<HTMLInputElement>): void {
        this.setState({ previewUrl: e.target.value });
    }

    protected handleUrlKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {
        if (e.key === 'Enter') {
            this.update();
        }
    }

    protected handleRefresh(): void {
        // Force iframe reload by briefly blanking the src
        this.update();
    }

    protected render(): React.ReactNode {
        const { routes, selectedRoute, previewUrl, scanning } = this.state;

        return (
            <div className="vibn-design-panel">
                {/* Top bar */}
                <div className="vibn-design-toolbar">
                    <span className="vibn-design-toolbar__title">Design</span>
                    <input
                        className="vibn-design-url-bar"
                        type="text"
                        value={previewUrl}
                        onChange={this.handleUrlChange.bind(this)}
                        onKeyDown={this.handleUrlKeyDown.bind(this)}
                        placeholder="http://localhost:3000"
                        spellCheck={false}
                    />
                    <button
                        className="vibn-design-btn"
                        title="Refresh preview"
                        onClick={this.handleRefresh.bind(this)}
                    >
                        <span className="codicon codicon-refresh" />
                    </button>
                    <button
                        className="vibn-design-btn"
                        title="Scan routes"
                        onClick={() => this.scanRoutes()}
                    >
                        <span className="codicon codicon-search" />
                    </button>
                </div>

                {/* Body */}
                <div className="vibn-design-body">
                    {/* Screen list */}
                    <div className="vibn-design-screens">
                        <div className="vibn-design-screens__header">
                            Screens
                            {scanning && <span className="vibn-design-spinner" />}
                        </div>

                        {!scanning && routes.length === 0 && (
                            <div className="vibn-design-screens__empty">
                                <span className="codicon codicon-info" />
                                <p>No Next.js routes found.</p>
                                <p>Open a project with an <code>app/</code> directory.</p>
                            </div>
                        )}

                        {routes.map(route => (
                            <div
                                key={route.path}
                                className={`vibn-design-route${selectedRoute === route.path ? ' vibn-design-route--active' : ''}`}
                                onClick={() => this.handleRouteClick(route)}
                                title={route.path}
                            >
                                <span className="codicon codicon-file-code" />
                                <span className="vibn-design-route__label">{route.label}</span>
                            </div>
                        ))}
                    </div>

                    {/* Preview */}
                    <div className="vibn-design-preview">
                        {previewUrl ? (
                            <iframe
                                className="vibn-design-iframe"
                                src={previewUrl}
                                title="Design preview"
                                sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-modals"
                            />
                        ) : (
                            <div className="vibn-design-preview__placeholder">
                                <span className="codicon codicon-browser" />
                                <p>Enter a URL above or start your dev server.</p>
                            </div>
                        )}
                    </div>
                </div>
            </div>
        );
    }
}
