import { RULE_PROFILES } from '../../../src/constants/profiles.js';
import { getRulesProfile } from '../../../src/utils/rule-transformer.js';
import path from 'path';

describe('MCP Configuration Validation', () => {
	describe('Profile MCP Configuration Properties', () => {
		const expectedMcpConfigurations = {
			cline: {
				shouldHaveMcp: false,
				expectedDir: '.clinerules',
				expectedConfigName: null,
				expectedPath: null
			},
			cursor: {
				shouldHaveMcp: true,
				expectedDir: '.cursor',
				expectedConfigName: 'mcp.json',
				expectedPath: '.cursor/mcp.json'
			},
			gemini: {
				shouldHaveMcp: true,
				expectedDir: '.gemini',
				expectedConfigName: 'settings.json',
				expectedPath: '.gemini/settings.json'
			},
			roo: {
				shouldHaveMcp: true,
				expectedDir: '.roo',
				expectedConfigName: 'mcp.json',
				expectedPath: '.roo/mcp.json'
			},
			trae: {
				shouldHaveMcp: false,
				expectedDir: '.trae',
				expectedConfigName: null,
				expectedPath: null
			},
			vscode: {
				shouldHaveMcp: true,
				expectedDir: '.vscode',
				expectedConfigName: 'mcp.json',
				expectedPath: '.vscode/mcp.json'
			},
			windsurf: {
				shouldHaveMcp: true,
				expectedDir: '.windsurf',
				expectedConfigName: 'mcp.json',
				expectedPath: '.windsurf/mcp.json'
			}
		};

		Object.entries(expectedMcpConfigurations).forEach(
			([profileName, expected]) => {
				test(`should have correct MCP configuration for ${profileName} profile`, () => {
					const profile = getRulesProfile(profileName);
					expect(profile).toBeDefined();
					expect(profile.mcpConfig).toBe(expected.shouldHaveMcp);
					expect(profile.profileDir).toBe(expected.expectedDir);
					expect(profile.mcpConfigName).toBe(expected.expectedConfigName);
					expect(profile.mcpConfigPath).toBe(expected.expectedPath);
				});
			}
		);
	});

	describe('MCP Configuration Path Consistency', () => {
		test('should ensure all profiles have consistent mcpConfigPath construction', () => {
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					const expectedPath = path.join(
						profile.profileDir,
						profile.mcpConfigName
					);
					expect(profile.mcpConfigPath).toBe(expectedPath);
				}
			});
		});

		test('should ensure no two profiles have the same MCP config path', () => {
			const mcpPaths = new Set();
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					expect(mcpPaths.has(profile.mcpConfigPath)).toBe(false);
					mcpPaths.add(profile.mcpConfigPath);
				}
			});
		});

		test('should ensure all MCP-enabled profiles use proper directory structure', () => {
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					expect(profile.mcpConfigPath).toMatch(/^\.[\w-]+\/[\w_.]+$/);
				}
			});
		});

		test('should ensure all profiles have required MCP properties', () => {
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toHaveProperty('mcpConfig');
				expect(profile).toHaveProperty('profileDir');
				expect(profile).toHaveProperty('mcpConfigName');
				expect(profile).toHaveProperty('mcpConfigPath');
			});
		});
	});

	describe('MCP Configuration File Names', () => {
		test('should use standard mcp.json for MCP-enabled profiles', () => {
			const standardMcpProfiles = ['cursor', 'roo', 'vscode', 'windsurf'];
			standardMcpProfiles.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile.mcpConfigName).toBe('mcp.json');
			});
		});

		test('should use custom settings.json for Gemini profile', () => {
			const profile = getRulesProfile('gemini');
			expect(profile.mcpConfigName).toBe('settings.json');
		});

		test('should have null config name for non-MCP profiles', () => {
			const clineProfile = getRulesProfile('cline');
			expect(clineProfile.mcpConfigName).toBe(null);

			const traeProfile = getRulesProfile('trae');
			expect(traeProfile.mcpConfigName).toBe(null);

			const claudeProfile = getRulesProfile('claude');
			expect(claudeProfile.mcpConfigName).toBe(null);

			const codexProfile = getRulesProfile('codex');
			expect(codexProfile.mcpConfigName).toBe(null);
		});
	});

	describe('Profile Directory Structure', () => {
		test('should ensure each profile has a unique directory', () => {
			const profileDirs = new Set();
			// Profiles that use root directory (can share the same directory)
			const rootProfiles = ['claude', 'codex', 'gemini'];

			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);

				// Root profiles can share the root directory for rules
				if (rootProfiles.includes(profileName) && profile.rulesDir === '.') {
					expect(profile.rulesDir).toBe('.');
				}

				// Profile directories should be unique (except for root profiles)
				if (!rootProfiles.includes(profileName) || profile.profileDir !== '.') {
					expect(profileDirs.has(profile.profileDir)).toBe(false);
					profileDirs.add(profile.profileDir);
				}
			});
		});

		test('should ensure profile directories follow expected naming convention', () => {
			// Profiles that use root directory for rules
			const rootRulesProfiles = ['claude', 'codex', 'gemini'];

			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);

				// Some profiles use root directory for rules
				if (
					rootRulesProfiles.includes(profileName) &&
					profile.rulesDir === '.'
				) {
					expect(profile.rulesDir).toBe('.');
				}

				// Profile directories (not rules directories) should follow the .name pattern
				// unless they are root profiles with profileDir = '.'
				if (profile.profileDir !== '.') {
					expect(profile.profileDir).toMatch(/^\.[\w-]+$/);
				}
			});
		});
	});

	describe('MCP Configuration Creation Logic', () => {
		test('should indicate which profiles require MCP configuration creation', () => {
			const mcpEnabledProfiles = RULE_PROFILES.filter((profileName) => {
				const profile = getRulesProfile(profileName);
				return profile.mcpConfig !== false;
			});

			expect(mcpEnabledProfiles).toContain('cursor');
			expect(mcpEnabledProfiles).toContain('gemini');
			expect(mcpEnabledProfiles).toContain('roo');
			expect(mcpEnabledProfiles).toContain('vscode');
			expect(mcpEnabledProfiles).toContain('windsurf');
			expect(mcpEnabledProfiles).not.toContain('claude');
			expect(mcpEnabledProfiles).not.toContain('cline');
			expect(mcpEnabledProfiles).not.toContain('codex');
			expect(mcpEnabledProfiles).not.toContain('trae');
		});

		test('should provide all necessary information for MCP config creation', () => {
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					expect(profile.mcpConfigPath).toBeDefined();
					expect(typeof profile.mcpConfigPath).toBe('string');
					expect(profile.mcpConfigPath.length).toBeGreaterThan(0);
				}
			});
		});
	});

	describe('MCP Configuration Path Usage Verification', () => {
		test('should verify that rule transformer functions use mcpConfigPath correctly', () => {
			// This test verifies that the mcpConfigPath property exists and is properly formatted
			// for use with the setupMCPConfiguration function
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					// Verify the path is properly formatted for path.join usage
					expect(profile.mcpConfigPath.startsWith('/')).toBe(false);
					expect(profile.mcpConfigPath).toContain('/');

					// Verify it matches the expected pattern: profileDir/configName
					const expectedPath = `${profile.profileDir}/${profile.mcpConfigName}`;
					expect(profile.mcpConfigPath).toBe(expectedPath);
				}
			});
		});

		test('should verify that mcpConfigPath is properly constructed for path.join usage', () => {
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					// Test that path.join works correctly with the mcpConfigPath
					const testProjectRoot = '/test/project';
					const fullPath = path.join(testProjectRoot, profile.mcpConfigPath);

					// Should result in a proper absolute path
					expect(fullPath).toBe(`${testProjectRoot}/${profile.mcpConfigPath}`);
					expect(fullPath).toContain(profile.profileDir);
					expect(fullPath).toContain(profile.mcpConfigName);
				}
			});
		});
	});

	describe('MCP Configuration Function Integration', () => {
		test('should verify that setupMCPConfiguration receives the correct mcpConfigPath parameter', () => {
			// This test verifies the integration between rule transformer and mcp-utils
			RULE_PROFILES.forEach((profileName) => {
				const profile = getRulesProfile(profileName);
				if (profile.mcpConfig !== false) {
					// Verify that the mcpConfigPath can be used directly with setupMCPConfiguration
					// The function signature is: setupMCPConfiguration(projectDir, mcpConfigPath)
					expect(profile.mcpConfigPath).toBeDefined();
					expect(typeof profile.mcpConfigPath).toBe('string');

					// Verify the path structure is correct for the new function signature
					const parts = profile.mcpConfigPath.split('/');
					expect(parts).toHaveLength(2); // Should be profileDir/configName
					expect(parts[0]).toBe(profile.profileDir);
					expect(parts[1]).toBe(profile.mcpConfigName);
				}
			});
		});
	});

	describe('MCP configuration validation', () => {
		const mcpProfiles = ['cursor', 'gemini', 'roo', 'windsurf', 'vscode'];
		const nonMcpProfiles = ['claude', 'codex', 'cline', 'trae'];

		test.each(mcpProfiles)(
			'should have valid MCP config for %s profile',
			(profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toBeDefined();
				expect(profile.mcpConfig).toBe(true);
				expect(profile.mcpConfigPath).toBeDefined();
				expect(typeof profile.mcpConfigPath).toBe('string');
			}
		);

		test.each(nonMcpProfiles)(
			'should not require MCP config for %s profile',
			(profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toBeDefined();
				expect(profile.mcpConfig).toBe(false);
			}
		);
	});

	describe('Profile structure validation', () => {
		const mcpProfiles = [
			'cursor',
			'gemini',
			'roo',
			'windsurf',
			'cline',
			'trae',
			'vscode'
		];
		const profilesWithLifecycle = ['claude'];
		const profilesWithoutLifecycle = ['codex'];

		test.each(mcpProfiles)(
			'should have file mappings for %s profile',
			(profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toBeDefined();
				expect(profile.fileMap).toBeDefined();
				expect(typeof profile.fileMap).toBe('object');
				expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0);
			}
		);

		test.each(profilesWithLifecycle)(
			'should have file mappings and lifecycle functions for %s profile',
			(profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toBeDefined();
				// Claude profile has both fileMap and lifecycle functions
				expect(profile.fileMap).toBeDefined();
				expect(typeof profile.fileMap).toBe('object');
				expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0);
				expect(typeof profile.onAddRulesProfile).toBe('function');
				expect(typeof profile.onRemoveRulesProfile).toBe('function');
				expect(typeof profile.onPostConvertRulesProfile).toBe('function');
			}
		);

		test.each(profilesWithoutLifecycle)(
			'should have file mappings without lifecycle functions for %s profile',
			(profileName) => {
				const profile = getRulesProfile(profileName);
				expect(profile).toBeDefined();
				// Codex profile has fileMap but no lifecycle functions (simplified)
				expect(profile.fileMap).toBeDefined();
				expect(typeof profile.fileMap).toBe('object');
				expect(Object.keys(profile.fileMap).length).toBeGreaterThan(0);
				expect(profile.onAddRulesProfile).toBeUndefined();
				expect(profile.onRemoveRulesProfile).toBeUndefined();
				expect(profile.onPostConvertRulesProfile).toBeUndefined();
			}
		);
	});
});
