const STATUS_COLORS = {
  running: 'green',
  warning: 'yellow',
  stopped: 'red',
  unknown: 'gray',
  disabled: 'gray'
};

function getProjectStatusColor(project) {
  if (!project) return STATUS_COLORS.unknown;
  if (project.running) return STATUS_COLORS.running;

  const status = String(project.status || '').toLowerCase();
  if (status.includes('start') || status.includes('warn')) return STATUS_COLORS.warning;
  if (status.includes('stop') || status.includes('fail') || status.includes('error')) return STATUS_COLORS.stopped;
  return STATUS_COLORS.unknown;
}

function buildEnvMenuUrl(project, action, params = {}) {
  const search = new URLSearchParams({ name: project.name || project.displayName || '' });
  Object.entries(params).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== '') {
      search.set(key, value);
    }
  });
  return `envmenu://project/${action}?${search.toString()}`;
}

function button(id, type, label, extra = {}) {
  return {
    id,
    type,
    label,
    enabled: extra.enabled !== false,
    color: extra.color || STATUS_COLORS.unknown,
    ...extra
  };
}

function currentProjectButton(project) {
  return button('current-project', 'envmenu', project.displayName || project.name, {
    color: getProjectStatusColor(project),
    url: buildEnvMenuUrl(project, 'select'),
    action: 'select',
    icon: project.icon || null
  });
}

function linkButton(project, label, url, id) {
  return button(id || `link-${label.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, 'link', label, {
    url,
    color: project.running ? STATUS_COLORS.running : STATUS_COLORS.disabled,
    envMenuUrl: buildEnvMenuUrl(project, 'open', { type: label.toLowerCase() })
  });
}

function envActionButton(project, label, action, color) {
  return button(`project-${action}`, 'envmenu', label, {
    action,
    url: buildEnvMenuUrl(project, action),
    color: color || getProjectStatusColor(project)
  });
}

function commandButton(project, label, command, id) {
  return button(id || `command-${label.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, 'command', label, {
    command,
    cwd: project.dir,
    color: project.running ? STATUS_COLORS.running : STATUS_COLORS.disabled
  });
}

function serviceStatusButton(project, service) {
  const name = typeof service === 'object' ? service.name : service;
  const status = typeof service === 'object' ? String(service.status || '') : (project.running ? 'running' : 'unknown');
  const color = status.toLowerCase() === 'running' ? STATUS_COLORS.running : getProjectStatusColor({ status, running: false });

  return button(`service-${name}`, 'status', name, {
    service: name,
    status,
    color
  });
}

function labelFromUrl(url, fallback) {
  try {
    return new URL(url).hostname || fallback;
  } catch (error) {
    return fallback;
  }
}

function normalizeCustomPages(project) {
  const streamDeck = project.streamDeck;
  if (!streamDeck || streamDeck.enabled === false || !streamDeck.pages) {
    return null;
  }

  const pages = {};
  Object.entries(streamDeck.pages).forEach(([pageName, actions]) => {
    if (!Array.isArray(actions)) return;
    pages[pageName] = actions.map((action, index) => ({
      id: action.id || `${pageName}-${index + 1}`,
      color: action.color || getProjectStatusColor(project),
      enabled: action.enabled !== false,
      ...action
    }));
  });

  return Object.keys(pages).length > 0 ? pages : null;
}

function buildProjectStreamDeckLayout(project) {
  if (!project) return null;

  const customPages = normalizeCustomPages(project);
  if (customPages) {
    return {
      project: summarizeProject(project),
      pages: customPages,
      source: 'project-config'
    };
  }

  const urls = Array.isArray(project.urls) ? project.urls : [];
  const siteUrl = urls[0] || null;
  const main = [
    currentProjectButton(project),
    ...(siteUrl ? [linkButton(project, 'Site', siteUrl, 'link-site')] : []),
    ...(siteUrl ? [linkButton(project, 'Admin', `${siteUrl.replace(/\/$/, '')}/admin`, 'link-admin')] : []),
    envActionButton(project, 'Start', 'start', STATUS_COLORS.running),
    envActionButton(project, 'Stop', 'stop', STATUS_COLORS.stopped),
    envActionButton(project, 'Restart', 'restart', STATUS_COLORS.warning),
    button('open-terminal', 'envmenu', 'Terminal', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'terminal' }),
      color: STATUS_COLORS.unknown
    }),
    button('open-finder', 'envmenu', 'Finder', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'folder' }),
      color: STATUS_COLORS.unknown
    })
  ];

  const links = urls.map((url, index) => linkButton(project, index === 0 ? 'Site' : labelFromUrl(url, `URL ${index + 1}`), url, `link-${index + 1}`));

  if (project.type === 'ddev') {
    links.push(linkButton(project, 'MailHog', `http://${project.name}.ddev.site:8026`, 'link-mailhog'));
  }

  if (project.addons) {
    project.addons
      .filter(addon => addon.hasWebUI)
      .forEach(addon => {
        links.push(linkButton(project, addon.label, `http://${project.name}.ddev.site:${addon.port}${addon.path || '/'}`, `addon-${addon.name}`));
      });
  }

  const development = [
    button('dev-terminal', 'envmenu', 'Terminal', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'terminal' })
    }),
    button('dev-vscode', 'envmenu', 'VS Code', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'vscode' })
    }),
    button('dev-logs', 'envmenu', 'Logs', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'logs' })
    }),
    ...(project.database ? [button('dev-database', 'envmenu', 'Database', {
      action: 'open',
      url: buildEnvMenuUrl(project, 'open', { type: 'database' })
    })] : []),
    ...(String(project.recipe || '').includes('drupal') ? [
      commandButton(project, 'Cache Clear', project.type === 'ddev' ? 'ddev drush cr' : 'lando drush cr', 'drupal-cache-clear'),
      commandButton(project, 'Updates', project.type === 'ddev' ? 'ddev drush updb -y' : 'lando drush updb -y', 'drupal-updates'),
      commandButton(project, 'Cron', project.type === 'ddev' ? 'ddev drush cron' : 'lando drush cron', 'drupal-cron')
    ] : [])
  ];

  const services = [
    serviceStatusButton(project, { name: project.type === 'ddev' ? 'web' : 'appserver', status: project.running ? 'running' : 'stopped' }),
    ...(project.database ? [serviceStatusButton(project, { name: project.type === 'ddev' ? 'db' : project.database.service || 'database', status: project.running ? 'running' : 'stopped' })] : []),
    ...((project.services || []).map(serviceStatusButton.bind(null, project)))
  ];

  return {
    project: summarizeProject(project),
    pages: {
      main,
      links,
      development,
      services
    },
    source: 'generated'
  };
}

function summarizeProject(project) {
  return {
    name: project.name,
    displayName: project.displayName || project.name,
    type: project.type,
    recipe: project.recipe,
    dir: project.dir,
    running: !!project.running,
    status: project.status || 'unknown',
    statusColor: getProjectStatusColor(project),
    icon: project.icon || null
  };
}

function buildStreamDeckState(projects, activeProjectName) {
  const projectList = Array.isArray(projects) ? projects : [];
  const activeProject = findProject(projectList, activeProjectName) || projectList[0] || null;

  return {
    activeProject: activeProject ? summarizeProject(activeProject) : null,
    layout: activeProject ? buildProjectStreamDeckLayout(activeProject) : null,
    projects: projectList.map(summarizeProject)
  };
}

function findProject(projects, projectName) {
  if (!projectName) return null;
  const target = String(projectName).toLowerCase();

  return (projects || []).find(project => {
    return [project.name, project.displayName, project.dir]
      .filter(Boolean)
      .some(value => String(value).toLowerCase() === target);
  }) || null;
}

module.exports = {
  STATUS_COLORS,
  buildEnvMenuUrl,
  buildProjectStreamDeckLayout,
  buildStreamDeckState,
  findProject,
  getProjectStatusColor
};
