import { describe, it, expect } from 'vitest';
import { render, fireEvent } from '@testing-library/react';
import { createStore, Provider } from 'jotai';
import React from 'react';
import Graph from 'graphology';
import { GroupNode } from '../../components/GroupNode';
import type { GraphNodeAttributes, GraphEdgeAttributes, UINodeState, DBGraphNode } from '../../core/types';
import { graphAtom, graphOptions, currentGraphIdAtom, graphUpdateVersionAtom } from '../../core/graph-store';
import { addNodeToLocalGraphAtom } from '../../core/graph-mutations';
import { collapsedGroupsAtom, setNodeParentAtom } from '../../core/group-store';

function makeNodeState(id: string, label = 'Group'): UINodeState {
	return {
		id,
		x: 0,
		y: 0,
		size: 15,
		width: 400,
		height: 300,
		color: '#ccc',
		label,
		zIndex: 0,
		dbData: {
			id,
			graph_id: 'test-graph',
			label,
			node_type: 'group',
			configuration: null,
			ui_properties: null,
			data: null,
			created_at: '2024-01-01',
			updated_at: '2024-01-01',
		},
		position: { x: 0, y: 0 },
		isDragging: false,
	};
}

function makeDbNode(id: string, x = 0, y = 0): DBGraphNode {
	return {
		id,
		graph_id: 'test-graph',
		label: `Node ${id}`,
		node_type: 'default',
		configuration: null,
		ui_properties: { x, y, width: 200, height: 100, size: 15, zIndex: 0 },
		data: null,
		created_at: '2024-01-01T00:00:00Z',
		updated_at: '2024-01-01T00:00:00Z',
	};
}

function setupStore() {
	const store = createStore();
	store.set(graphAtom, new Graph<GraphNodeAttributes, GraphEdgeAttributes>(graphOptions));
	store.set(currentGraphIdAtom, 'test-graph');
	return store;
}

function renderWithStore(store: ReturnType<typeof createStore>, ui: React.ReactElement) {
	return render(<Provider store={store}>{ui}</Provider>);
}

describe('GroupNode', () => {
	it('renders with label', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));

		const { getByText } = renderWithStore(
			store,
			<GroupNode node={makeNodeState('group', 'My Group')} />,
		);

		expect(getByText('My Group')).toBeInTheDocument();
	});

	it('shows child count', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c1'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c2'));
		store.set(setNodeParentAtom, { nodeId: 'c1', parentId: 'group' });
		store.set(setNodeParentAtom, { nodeId: 'c2', parentId: 'group' });

		const { getByText } = renderWithStore(
			store,
			<GroupNode node={makeNodeState('group')} />,
		);

		expect(getByText('2 nodes')).toBeInTheDocument();
	});

	it('toggles collapsed state on click', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c1'));
		store.set(setNodeParentAtom, { nodeId: 'c1', parentId: 'group' });

		const { getByText } = renderWithStore(
			store,
			<GroupNode node={makeNodeState('group')} />,
		);

		// Initially expanded (▼ icon)
		expect(getByText('▼')).toBeInTheDocument();

		// Click the header to collapse
		fireEvent.click(getByText('▼'));

		// Now collapsed (▶ icon)
		expect(store.get(collapsedGroupsAtom).has('group')).toBe(true);
		expect(getByText('▶')).toBeInTheDocument();
	});

	it('shows collapsed summary when collapsed', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c1'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c2'));
		store.set(addNodeToLocalGraphAtom, makeDbNode('c3'));
		store.set(setNodeParentAtom, { nodeId: 'c1', parentId: 'group' });
		store.set(setNodeParentAtom, { nodeId: 'c2', parentId: 'group' });
		store.set(setNodeParentAtom, { nodeId: 'c3', parentId: 'group' });

		// Pre-collapse the group
		store.set(collapsedGroupsAtom, new Set(['group']));

		const { getByText } = renderWithStore(
			store,
			<GroupNode node={makeNodeState('group')} />,
		);

		expect(getByText('3 collapsed nodes')).toBeInTheDocument();
	});

	it('applies selected border', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));

		const { container } = renderWithStore(
			store,
			<GroupNode node={makeNodeState('group')} isSelected />,
		);

		const div = container.firstChild as HTMLElement;
		expect(div.style.borderStyle).toBe('solid');
	});

	it('supports custom renderHeader', () => {
		const store = setupStore();
		store.set(addNodeToLocalGraphAtom, makeDbNode('group'));

		const { getByText } = renderWithStore(
			store,
			<GroupNode
				node={makeNodeState('group')}
				renderHeader={({ childCount }) => <span>Custom: {childCount}</span>}
			/>,
		);

		expect(getByText('Custom: 0')).toBeInTheDocument();
	});
});
