const { spawn } = require('child_process');

const port = 3999;
const baseUrl = `http://127.0.0.1:${port}`;
const child = spawn(process.execPath, ['server/index.js'], {
  cwd: process.cwd(),
  env: { ...process.env, PORT: String(port) },
  stdio: ['ignore', 'pipe', 'pipe']
});

function wait(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function request(path, options = {}) {
  const response = await fetch(`${baseUrl}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(options.headers || {})
    }
  });
  const body = await response.json().catch(() => ({}));
  if (!response.ok) {
    throw new Error(`${path} failed: ${response.status} ${JSON.stringify(body)}`);
  }
  return body;
}

async function waitForServer() {
  for (let attempt = 0; attempt < 60; attempt += 1) {
    try {
      await request('/api/health');
      return;
    } catch {
      await wait(250);
    }
  }
  throw new Error('Server did not start');
}

async function main() {
  await waitForServer();
  const login = await request('/api/auth/login', {
    method: 'POST',
    body: JSON.stringify({
      email: 'admin@mixedassets.local',
      password: process.env.MIXEDASSETS_ADMIN_PASSWORD || 'ChangeMe123!'
    })
  });

  const auth = { Authorization: `Bearer ${login.token}` };
  const profile = await request('/api/profile', { headers: auth });
  if (profile.preferences.theme !== 'mixedAssetsDark') {
    throw new Error(`Expected default dark theme, found ${profile.preferences.theme}`);
  }
  const updatedProfile = await request('/api/profile', {
    method: 'PUT',
    headers: auth,
    body: JSON.stringify({ preferences: { theme: 'mixedAssetsDark' } })
  });
  if (updatedProfile.preferences.theme !== 'mixedAssetsDark') {
    throw new Error('Profile theme preference did not persist');
  }

  const taxRules = await request('/api/tax-rules', { headers: auth });
  const activeRule = taxRules.ruleSets.find((rule) => rule.active) || taxRules.ruleSets[0];
  const methodCount = activeRule?.rules_json?.methods?.length || 0;
  if (methodCount !== 68) {
    throw new Error(`Expected 68 depreciation methods, found ${methodCount}`);
  }

  const suffix = Date.now().toString().slice(-6);
  const accessControl = await request('/api/access-control', { headers: auth });
  if (!accessControl.roles.includes('admin') || !accessControl.roleCapabilities.some((capability) => capability.key === 'users')) {
    throw new Error('Access control role matrix was not returned correctly');
  }

  const teamResult = await request('/api/teams', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      name: `Smoke Team ${suffix}`,
      description: 'Smoke test RBAC team'
    })
  });
  const userResult = await request('/api/users', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      team_id: teamResult.team.id,
      name: 'Smoke Test Viewer',
      email: `viewer-${suffix}@example.com`,
      password: 'ChangeMe123!',
      role: 'viewer',
      status: 'active'
    })
  });
  const updatedUser = await request(`/api/users/${userResult.user.id}`, {
    method: 'PUT',
    headers: auth,
    body: JSON.stringify({
      team_id: teamResult.team.id,
      name: 'Smoke Test Operator',
      email: `operator-${suffix}@example.com`,
      role: 'operations',
      status: 'active'
    })
  });
  if (updatedUser.user.role !== 'operations' || updatedUser.user.team_id !== teamResult.team.id) {
    throw new Error('User role or team update did not persist');
  }

  await request('/api/templates', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      name: `Smoke template ${suffix}`,
      description: 'Template custom field smoke test',
      defaults: { category: 'Computer Equipment', useful_life_months: 60, depreciation_method: 'macrs_gds_200db_5' },
      custom_fields: [
        { key: 'employee_id', label: 'Employee ID', type: 'text', required: true },
        { key: 'calibration_due', label: 'Calibration due', type: 'date', required: false }
      ]
    })
  });
  const templates = await request('/api/templates', { headers: auth });
  const smokeTemplate = templates.templates.find((template) => template.name === `Smoke template ${suffix}`);
  if (!smokeTemplate || smokeTemplate.custom_fields.length !== 2) {
    throw new Error('Template custom fields were not saved or returned correctly');
  }

  const assetResult = await request('/api/assets', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      asset_id: `T-${suffix}`,
      description: 'Smoke test workstation',
      category: 'Computer Equipment',
      acquisition_cost: 2400,
      acquired_date: '2026-01-05',
      in_service_date: '2026-01-05',
      useful_life_months: 60,
      depreciation_method: 'macrs_gds_200db_5'
    })
  });

  const employeeResult = await request('/api/employees', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      employee_number: `EMP-${suffix}`,
      name: 'Smoke Test Employee',
      email: `employee-${suffix}@example.com`,
      department: 'Operations',
      location: 'Headquarters'
    })
  });

  await request('/api/assignments', {
    method: 'POST',
    headers: auth,
    body: JSON.stringify({
      asset_id: assetResult.asset.id,
      employee_id: employeeResult.employee.id,
      notes: 'Smoke assignment'
    })
  });

  const assignments = await request('/api/assignments?active=true', { headers: auth });
  if (!assignments.assignments.some((assignment) => assignment.asset_id === assetResult.asset.id && assignment.employee_id === employeeResult.employee.id)) {
    throw new Error('Asset assignment was not saved or returned correctly');
  }

  const workday = await request('/api/workday/connection', {
    method: 'PUT',
    headers: auth,
    body: JSON.stringify({
      name: 'Smoke Workday',
      tenant: 'smoke',
      base_url: 'https://example.workday.com',
      token_url: 'https://example.workday.com/oauth2/token',
      client_id: 'client',
      client_secret: 'secret',
      workers_path: '/workers',
      enabled: false
    })
  });
  if (!workday.connection.configured) {
    throw new Error('Workday connection configuration did not persist');
  }

  const report = await request('/api/reports/depreciation?year=2026&book=GAAP', { headers: auth });
  if (!Array.isArray(report.rows) || !report.rows.length) {
    throw new Error('Depreciation report returned no rows');
  }
  console.log('Smoke test passed');
}

main()
  .catch((error) => {
    console.error(error.message);
    process.exitCode = 1;
  })
  .finally(() => {
    child.kill('SIGTERM');
  });
