const fc = require('fast-check');
const DependencyChecker = require('./dependency-checker');

/**
 * Feature: dashcaddy-installer, Property 2: Dependency Verification
 * For any system state, the installer should accurately report whether Docker 
 * is installed and running, and whether Caddy is installed.
 * Validates: Requirements 1.2, 1.3
 */
describe('Property 2: Dependency Verification', () => {
  let checker;

  beforeEach(() => {
    checker = new DependencyChecker();
  });

  test('checkDocker always returns valid structure', async () => {
    // Skip if Docker commands are too slow
    const quickCheck = await checker.checkDocker();
    if (!quickCheck.installed) {
      // If Docker not installed, just verify the structure is correct
      expect(quickCheck.installed).toBe(false);
      expect(quickCheck.running).toBe(false);
      return;
    }

    await fc.assert(
      fc.asyncProperty(
        fc.constant(null),
        async () => {
          const result = await checker.checkDocker();
          
          // Must have required fields
          const hasRequiredFields = 
            typeof result.installed === 'boolean' &&
            typeof result.running === 'boolean' &&
            (result.version === null || typeof result.version === 'string');
          
          // If installed, version should be present
          const versionConsistent = !result.installed || result.version !== null;
          
          // If not installed, cannot be running
          const runningConsistent = !result.running || result.installed;
          
          return hasRequiredFields && versionConsistent && runningConsistent;
        }
      ),
      { numRuns: 5 } // Very few runs since Docker commands are slow
    );
  }, 60000); // 60 second timeout

  test('checkCaddy always returns valid structure', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.constant(null),
        async () => {
          const result = await checker.checkCaddy();
          
          // Must have required fields
          const hasRequiredFields = 
            typeof result.installed === 'boolean' &&
            (result.version === null || typeof result.version === 'string') &&
            (result.path === null || typeof result.path === 'string');
          
          // If installed, version should be present
          const versionConsistent = !result.installed || result.version !== null;
          
          return hasRequiredFields && versionConsistent;
        }
      ),
      { numRuns: 50 }
    );
  });

  test('dependency check results are deterministic', async () => {
    // Skip if Docker commands are too slow
    const quickCheck = await checker.checkDocker();
    if (!quickCheck.installed) {
      // If Docker not installed, just verify consistency
      const check2 = await checker.checkDocker();
      expect(check2.installed).toBe(false);
      return;
    }

    await fc.assert(
      fc.asyncProperty(
        fc.constant(null),
        async () => {
          const result1 = await checker.checkDocker();
          const result2 = await checker.checkDocker();
          
          // Same system state should return same results
          return (
            result1.installed === result2.installed &&
            result1.running === result2.running &&
            result1.version === result2.version
          );
        }
      ),
      { numRuns: 3 } // Very few runs since this is expensive
    );
  }, 60000); // 60 second timeout

  test('getDockerInstallInstructions returns valid structure for any platform', () => {
    fc.assert(
      fc.property(
        fc.constantFrom('windows', 'macos', 'linux', 'unknown'),
        (platform) => {
          const instructions = checker.getDockerInstallInstructions(platform);
          
          return (
            typeof instructions === 'object' &&
            typeof instructions.title === 'string' &&
            Array.isArray(instructions.steps) &&
            instructions.steps.length > 0 &&
            typeof instructions.url === 'string' &&
            typeof instructions.requiresWSL2 === 'boolean'
          );
        }
      ),
      { numRuns: 100 }
    );
  });

  test('getCaddyInstallInstructions returns valid structure for any platform', () => {
    fc.assert(
      fc.property(
        fc.constantFrom('windows', 'macos', 'linux', 'unknown'),
        (platform) => {
          const instructions = checker.getCaddyInstallInstructions(platform);
          
          return (
            typeof instructions === 'object' &&
            typeof instructions.title === 'string' &&
            Array.isArray(instructions.steps) &&
            instructions.steps.length > 0 &&
            typeof instructions.url === 'string' &&
            typeof instructions.automated === 'boolean'
          );
        }
      ),
      { numRuns: 100 }
    );
  });

  test('Windows Docker instructions always mention WSL2', () => {
    const instructions = checker.getDockerInstallInstructions('windows');
    
    expect(instructions.requiresWSL2).toBe(true);
    expect(instructions.wsl2Instructions).toBeDefined();
    expect(Array.isArray(instructions.wsl2Instructions)).toBe(true);
  });

  test('macOS Caddy instructions support automation', () => {
    const instructions = checker.getCaddyInstallInstructions('macos');
    
    expect(instructions.automated).toBe(true);
    expect(instructions.command).toBeDefined();
    expect(instructions.command).toContain('brew');
  });

  test('Linux instructions include package manager options', () => {
    fc.assert(
      fc.property(
        fc.constantFrom('docker', 'caddy'),
        (tool) => {
          const instructions = tool === 'docker' 
            ? checker.getDockerInstallInstructions('linux')
            : checker.getCaddyInstallInstructions('linux');
          
          return (
            typeof instructions.packageManagers === 'object' &&
            Object.keys(instructions.packageManagers).length > 0
          );
        }
      ),
      { numRuns: 100 }
    );
  });

  test('executeCommand handles any command string', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.string({ minLength: 1, maxLength: 50 }),
        async (command) => {
          try {
            const result = await checker.executeCommand(command);
            
            // Must return valid structure
            return (
              typeof result === 'object' &&
              typeof result.success === 'boolean' &&
              typeof result.stdout === 'string' &&
              typeof result.stderr === 'string'
            );
          } catch (error) {
            // Some commands might fail, that's okay
            return true;
          }
        }
      ),
      { numRuns: 50 } // Reduced since this executes actual commands
    );
  });

  test('detectLinuxDistro returns valid distro name', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.constant(null),
        async () => {
          const distro = await checker.detectLinuxDistro();
          const validDistros = ['ubuntu', 'fedora', 'arch', 'unknown'];
          
          return (
            typeof distro === 'string' &&
            validDistros.includes(distro)
          );
        }
      ),
      { numRuns: 50 }
    );
  });

  test('installDocker always returns result with instructions', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.constantFrom('windows', 'macos', 'linux'),
        async (platform) => {
          const result = await checker.installDocker(platform);
          
          return (
            typeof result === 'object' &&
            typeof result.success === 'boolean' &&
            typeof result.automated === 'boolean' &&
            typeof result.message === 'string' &&
            typeof result.instructions === 'object'
          );
        }
      ),
      { numRuns: 100 }
    );
  });

  test('installCaddy returns appropriate result for platform', async () => {
    await fc.assert(
      fc.asyncProperty(
        fc.constantFrom('windows', 'macos', 'linux'),
        async (platform) => {
          const result = await checker.installCaddy(platform);
          
          const hasRequiredFields = 
            typeof result === 'object' &&
            typeof result.success === 'boolean' &&
            typeof result.automated === 'boolean' &&
            typeof result.message === 'string';
          
          // Windows should not be automated
          const windowsCorrect = platform !== 'windows' || result.automated === false;
          
          // macOS should attempt automation (Linux may or may not depending on distro detection)
          const macCorrect = platform !== 'macos' || result.automated === true;
          
          return hasRequiredFields && windowsCorrect && macCorrect;
        }
      ),
      { numRuns: 100 }
    );
  }, 30000); // 30 second timeout
});
