import axios from 'axios';
import { IncidentParams, IncidentResult, GetIncidentsParams, GetIncidentsResult } from '../models/incident';
import { log } from '../utils/logger';

// Tool definition for creating an incident
export const CreateIncidentTool = {
  name: 'create_incident',
  description: 'Create a new incident in ServiceNow',
  inputSchema: {
    type: 'object',
    properties: {
      short_description: {
        type: 'string',
        description: 'Short description of the incident'
      },
      description: {
        type: 'string',
        description: 'Detailed description of the incident'
      },
      urgency: {
        type: 'string',
        enum: ['1', '2', '3'],
        description: 'Urgency of the incident (1=high, 2=medium, 3=low)'
      },
      impact: {
        type: 'string',
        enum: ['1', '2', '3'],
        description: 'Impact of the incident (1=high, 2=medium, 3=low)'
      },
      priority: {
        type: 'string',
        enum: ['1', '2', '3', '4', '5'],
        description: 'Priority of the incident (1=critical, 5=planning)'
      },
      state: {
        type: 'string',
        enum: ['New', 'In Progress', 'Resolved', 'On Hold', 'Closed', 'Cancelled'],
        description: 'State of the incident'
      }
    },
    required: ['short_description']
  }
};

// Logic for creating an incident
export async function createIncident(params: any = {}): Promise<any> {
  try {
    log(`createIncident called with params: ${JSON.stringify(params)}`);
    
    // Extract parameters
    const short_description = params.short_description;
    const description = params.description || '';
    const urgency = params.urgency;
    const impact = params.impact;
    const priority = params.priority;
    const state = params.state;
    
    // Validate required field
    if (!short_description) {
      return { 
        content: [{ 
          type: 'text', 
          text: 'Error: short_description parameter is required' 
        }] 
      };
    }
    
    const instanceUrl = process.env.SERVICENOW_INSTANCE_URL;
    const username = process.env.SERVICENOW_USERNAME;
    const password = process.env.SERVICENOW_PASSWORD;
    const senderEmail = process.env.SERVICENOW_DEFAULT_SENDER_EMAIL;
    
    if (!instanceUrl || !username || !password) {
      return { 
        content: [{ 
          type: 'text', 
          text: 'Error: Missing ServiceNow credentials. Please check environment variables.' 
        }] 
      };
    }
    
    log(`Creating incident: ${short_description}`);
    
    // Build the incident payload - only include fields that have values
    const incidentPayload: any = {
      short_description,
      description,
      caller_email: senderEmail
    };
    
    // Only add optional fields if they have values
    if (urgency) incidentPayload.urgency = urgency;
    if (impact) incidentPayload.impact = impact;
    if (priority) incidentPayload.priority = priority;
    if (state) incidentPayload.state = state;
    
    log(`Incident payload: ${JSON.stringify(incidentPayload)}`);
    
    const response = await axios.post(
      `${instanceUrl}/api/now/table/incident`,
      incidentPayload,
      {
        auth: { username, password },
        headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }
      }
    );
    
    const incident = response.data.result;
    log(`Incident created successfully: ${incident.number}`);
    
    return {
      content: [{
        type: 'text',
        text: `Incident created successfully:
- Number: ${incident.number}
- System ID: ${incident.sys_id}
- Created: ${incident.sys_created_on}
- Short Description: ${incident.short_description}
- State: ${incident.state || 'New'}
- Priority: ${incident.priority || 'Not Set'}
- Urgency: ${incident.urgency || 'Not Set'}
- Impact: ${incident.impact || 'Not Set'}`
      }]
    };
  } catch (error: any) {
    log(`Error creating incident: ${error.message}`);
    if (error.response) {
      log(`Error response status: ${error.response.status}`);
      log(`Error response data: ${JSON.stringify(error.response.data)}`);
    }
    
    let errorMessage = `Error creating incident: ${error.message}`;
    if (error.response?.status === 401) {
      errorMessage += '\nAuthentication error. Please verify ServiceNow credentials.';
    } else if (error.response?.status === 403) {
      errorMessage += '\nPermission error. Please verify ServiceNow user roles.';
    } else if (error.response?.status === 400) {
      errorMessage += '\nBad request. Please check the field values and formats.';
      if (error.response.data?.error?.message) {
        errorMessage += `\nServiceNow error: ${error.response.data.error.message}`;
      }
    }
    
    return { 
      content: [{ 
        type: 'text', 
        text: errorMessage 
      }] 
    };
  }
}

// Tool definition for getting incidents
export const GetIncidentsTool = {
  name: 'get_incidents',
  description: 'Get incidents from ServiceNow based on specified criteria',
  inputSchema: {
    type: 'object',
    properties: {
      assignment_group: {
        type: 'string',
        description: 'Name of the assignment group'
      },
      active: {
        type: 'boolean',
        description: 'Filter by active status'
      },
      description: {
        type: 'string',
        description: 'Keyword to search for in the description'
      },
      number: {
        type: 'string',
        description: 'Incident number to search for'
      },
      urgency: {
        type: 'string',
        description: 'Filter by urgency level (1=high, 2=medium, 3=low)'
      },
      priority: {
        type: 'string',
        description: 'Filter by priority level (1=critical, 5=planning)'
      },
      state: {
        type: 'string',
        description: 'State of the incident ("New", "In Progress", "Resolved", "On Hold", "Closed", "Cancelled")'
      },
      limit: {
        type: 'number',
        description: 'Maximum number of incidents to return (default: 50)'
      }
    }
  }
};

// Logic for getting incidents
export async function getIncidents(params: any = {}): Promise<any> {
  try {
    log(`getIncidents called with params: ${JSON.stringify(params)}`);
    
    const instanceUrl = process.env.SERVICENOW_INSTANCE_URL;
    const username = process.env.SERVICENOW_USERNAME;
    const password = process.env.SERVICENOW_PASSWORD;

    if (!instanceUrl || !username || !password) {
      return { 
        content: [{ 
          type: 'text', 
          text: 'Error: Missing ServiceNow credentials. Please check environment variables.' 
        }] 
      };
    }

    // Build the query string dynamically
    const queryParts: string[] = [];
    
    if (params.number) {
      queryParts.push(`number=${params.number}`);
    }
    if (params.assignment_group) {
      queryParts.push(`assignment_group.name=${params.assignment_group}`);
    }
    if (typeof params.active === 'boolean') {
      queryParts.push(`active=${params.active}`);
    }
    if (params.description) {
      queryParts.push(`descriptionCONTAINS${params.description}`);
    }
    if (params.urgency) {
      queryParts.push(`urgency=${params.urgency}`);
    }
    if (params.priority) {
      queryParts.push(`priority=${params.priority}`);
    }
    if (params.state) {
      queryParts.push(`state=${params.state}`);
    }
    
    const query = queryParts.join('^');

    // Build request params
    const requestParams: any = {
      sysparm_fields: 'number,sys_id,short_description,description,state,priority,urgency,assignment_group.display_value,caller_id.display_value,sys_created_on,active',
      sysparm_limit: params.limit || 50,
      sysparm_order_by: '-sys_created_on'
    };
    
    if (query) {
      requestParams.sysparm_query = query;
    }

    log(`Querying incidents with: ${JSON.stringify(requestParams)}`);

    const response = await axios.get(
      `${instanceUrl}/api/now/table/incident`,
      {
        params: requestParams,
        auth: { username, password },
        headers: { 'Accept': 'application/json' }
      }
    );

    log(`ServiceNow response status: ${response.status}`);

    const incidents = response.data.result;
    if (!incidents) {
      return { 
        content: [{ 
          type: 'text', 
          text: 'Error: Invalid response from ServiceNow.' 
        }] 
      };
    }

    log(`Found ${incidents.length} incidents`);

    if (incidents.length === 0) {
      return {
        content: [{
          type: 'text',
          text: 'No incidents found matching the specified criteria.'
        }]
      };
    }

    // Format incidents for display
    const formattedIncidents = incidents.map((incident: any) => {
      return `• **${incident.number}** - ${incident.short_description}
  State: ${incident.state || 'Unknown'}
  Priority: ${incident.priority || 'Not Set'}
  Urgency: ${incident.urgency || 'Not Set'}
  Assignment Group: ${incident.assignment_group?.display_value || 'Unassigned'}
  Caller: ${incident.caller_id?.display_value || 'Unknown'}
  Created: ${incident.sys_created_on}
  Active: ${incident.active || 'Unknown'}`;
    }).join('\n\n');

    return {
      content: [{
        type: 'text',
        text: `Found ${incidents.length} incident(s):\n\n${formattedIncidents}`
      }]
    };

  } catch (error: any) {
    log(`Error getting incidents: ${error.message}`);
    if (error.response) {
      log(`Error response status: ${error.response.status}`);
      log(`Error response data: ${JSON.stringify(error.response.data)}`);
    }
    
    let errorMessage = `Error retrieving incidents: ${error.message}`;
    if (error.response?.status === 401) {
      errorMessage += '\nAuthentication error. Please verify ServiceNow credentials.';
    } else if (error.response?.status === 403) {
      errorMessage += '\nPermission error. Please verify ServiceNow user roles.';
    } else if (error.response?.status === 400) {
      errorMessage += '\nBad request. Please check the query parameters.';
    }
    
    return { 
      content: [{ 
        type: 'text', 
        text: errorMessage 
      }] 
    };
  }
}

// Collection of all incident-related tools
export const incidentTools = {
  [CreateIncidentTool.name]: {
    definition: CreateIncidentTool,
    execute: createIncident
  },
  [GetIncidentsTool.name]: {
    definition: GetIncidentsTool,
    execute: getIncidents
  }
};