import axios from 'axios';
import httpClient from '../config/httpClient';
import toolConfigService, { VikunjaConfig } from './toolConfig.service';
import logger from '../utils/logger';

export interface VikunjaTask {
  id: number;
  title: string;
  done: boolean;
  due_date: string | null;
  priority: number;
  project_id: number;
}

export interface VikunjaProject {
  id: number;
  title: string;
}

/**
 * Validates that a URL is safe to use as an outbound service endpoint.
 * Rejects non-http(s) protocols and private/loopback IP ranges to prevent SSRF.
 */
function isValidServiceUrl(raw: string): boolean {
  let parsed: URL;
  try {
    parsed = new URL(raw);
  } catch {
    return false;
  }

  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    return false;
  }

  const hostname = parsed.hostname.toLowerCase();

  // Reject plain loopback / localhost names
  if (hostname === 'localhost' || hostname === '::1') {
    return false;
  }

  // Reject numeric IPv4 private / loopback / link-local ranges
  const ipv4Parts = hostname.split('.');
  if (ipv4Parts.length === 4) {
    const [a, b] = ipv4Parts.map(Number);
    if (
      a === 127 ||                        // 127.0.0.0/8  loopback
      a === 10 ||                         // 10.0.0.0/8   private
      (a === 172 && b >= 16 && b <= 31) || // 172.16.0.0/12 private
      (a === 192 && b === 168) ||         // 192.168.0.0/16 private
      (a === 169 && b === 254)            // 169.254.0.0/16 link-local
    ) {
      return false;
    }
  }

  return true;
}

function buildHeaders(config: VikunjaConfig): Record<string, string> {
  return {
    'Authorization': `Bearer ${config.apiToken}`,
    'Content-Type': 'application/json',
  };
}

async function getMyTasks(): Promise<VikunjaTask[]> {
  const config = await toolConfigService.getVikunjaConfig();
  if (!config.url || !isValidServiceUrl(config.url)) {
    throw new Error('VIKUNJA_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get<VikunjaTask[]>(
      `${config.url}/api/v1/tasks/all`,
      { headers: buildHeaders(config) },
    );
    return (response.data ?? []).filter((t) => !t.done);
  } catch (error) {
    if (axios.isAxiosError(error)) {
      logger.error('Vikunja getMyTasks failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
    }
    logger.error('VikunjaService.getMyTasks failed', { error });
    throw new Error('Failed to fetch Vikunja tasks');
  }
}

async function getOverdueTasks(): Promise<VikunjaTask[]> {
  const tasks = await getMyTasks();
  const now = new Date();
  return tasks.filter((t) => {
    if (!t.due_date || t.due_date.startsWith('0001-')) return false;
    return new Date(t.due_date) < now;
  });
}

async function getProjects(): Promise<VikunjaProject[]> {
  const config = await toolConfigService.getVikunjaConfig();
  if (!config.url || !isValidServiceUrl(config.url)) {
    throw new Error('VIKUNJA_URL is not configured or is not a valid service URL');
  }

  try {
    const response = await httpClient.get<VikunjaProject[]>(
      `${config.url}/api/v1/projects`,
      { headers: buildHeaders(config) },
    );
    return response.data ?? [];
  } catch (error) {
    if (axios.isAxiosError(error)) {
      logger.error('Vikunja getProjects failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
    }
    logger.error('VikunjaService.getProjects failed', { error });
    throw new Error('Failed to fetch Vikunja projects');
  }
}

async function createTask(projectId: number, title: string, dueDate?: string): Promise<VikunjaTask> {
  const config = await toolConfigService.getVikunjaConfig();
  if (!config.url || !isValidServiceUrl(config.url)) {
    throw new Error('VIKUNJA_URL is not configured or is not a valid service URL');
  }

  try {
    const body: Record<string, unknown> = { title };
    if (dueDate) {
      body.due_date = dueDate;
    }
    const response = await httpClient.put<VikunjaTask>(
      `${config.url}/api/v1/projects/${projectId}/tasks`,
      body,
      { headers: buildHeaders(config) },
    );
    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      logger.error('Vikunja createTask failed', {
        status: error.response?.status,
        statusText: error.response?.statusText,
      });
    }
    logger.error('VikunjaService.createTask failed', { error });
    throw new Error('Failed to create Vikunja task');
  }
}

export default { getMyTasks, getOverdueTasks, getProjects, createTask };
