#!/usr/bin/env node
import axios, { AxiosInstance, AxiosError } from 'axios';

// Use type declarations to make TypeScript happy
declare module '@modelcontextprotocol/sdk' {
  export class Server {
    constructor(info: any, options: any);
    connect(transport: any): Promise<void>;
    close(): Promise<void>;
    setRequestHandler(schema: any, handler: Function): void;
    onerror: (error: any) => void;
  }
  
  export class StdioServerTransport {
    constructor();
  }
  
  export const CallToolRequestSchema: any;
  export const ListToolsRequestSchema: any;
  export const ErrorCode: {
    MethodNotFound: string;
  };
  
  export class McpError extends Error {
    constructor(code: string, message: string);
  }
}

// Import dynamically to avoid TypeScript errors
const MCP_SDK = '@modelcontextprotocol/sdk';

// SMS.ir API base URL
const BASE_URL = 'https://api.sms.ir/v1';

// Parameter interfaces
interface SendSmsParams {
  mobile: string;
  message: string;
  lineNumber?: string;
  sendDateTime?: string;
}

interface SendBulkSmsParams {
  mobiles: string[];
  messageText: string;
  lineNumber?: string;
  sendDateTime?: string;
}

interface VerificationParams {
  mobile: string;
  templateId: string;
  parameters: Array<{name: string; value: string}>;
}

class SmsIrServer {
  private server: Server;
  private axiosInstance: AxiosInstance;

  constructor(apiKey: string) {
    if (!apiKey) {
      throw new Error('SMS_IR_API_KEY is required');
    }

    this.server = new Server(
      {
        name: 'sms-ir-server',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    // Configure axios instance with default headers and base URL
    this.axiosInstance = axios.create({
      baseURL: BASE_URL,
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'text/plain',
        'x-api-key': apiKey,
      }
    });

    this.setupToolHandlers();
    
    // Error handling
    this.server.onerror = (error: any) => console.error('[MCP Error]', error);
    process.on('SIGINT', async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  private setupToolHandlers() {
    // List available tools
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'send_sms',
          description: 'Send a SMS message to a single recipient',
          inputSchema: {
            type: 'object',
            properties: {
              mobile: {
                type: 'string',
                description: 'Recipient mobile number (e.g., 09121234567)',
              },
              message: {
                type: 'string',
                description: 'Message content',
              },
              lineNumber: {
                type: 'string',
                description: 'Sender line number (optional)',
              },
              sendDateTime: {
                type: 'string',
                description: 'Scheduled date and time for sending the message (optional, ISO format)',
              },
            },
            required: ['mobile', 'message'],
          },
        },
        {
          name: 'send_bulk_sms',
          description: 'Send the same SMS message to multiple recipients',
          inputSchema: {
            type: 'object',
            properties: {
              mobiles: {
                type: 'array',
                items: {
                  type: 'string',
                },
                description: 'Array of recipient mobile numbers',
              },
              messageText: {
                type: 'string',
                description: 'Message content to send to all recipients',
              },
              lineNumber: {
                type: 'string',
                description: 'Sender line number (optional)',
              },
              sendDateTime: {
                type: 'string',
                description: 'Scheduled date and time for sending the message (optional, ISO format)',
              },
            },
            required: ['mobiles', 'messageText'],
          },
        },
        {
          name: 'send_verification_code',
          description: 'Send a verification code SMS using a template',
          inputSchema: {
            type: 'object',
            properties: {
              mobile: {
                type: 'string',
                description: 'Recipient mobile number',
              },
              templateId: {
                type: 'string',
                description: 'Template ID from SMS.ir panel',
              },
              parameters: {
                type: 'array',
                items: {
                  type: 'object',
                  properties: {
                    name: {
                      type: 'string',
                      description: 'Parameter name as defined in the template',
                    },
                    value: {
                      type: 'string',
                      description: 'Parameter value to replace in the template',
                    },
                  },
                  required: ['name', 'value'],
                },
                description: 'Array of parameters to substitute in the template',
              },
            },
            required: ['mobile', 'templateId', 'parameters'],
          },
        },
        {
          name: 'check_credit',
          description: 'Check the remaining credit in your SMS.ir account',
          inputSchema: {
            type: 'object',
            properties: {},
            required: [],
          },
        },
      ],
    }));

    // Handle tool calls
    this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
      try {
        switch (request.params.name) {
          case 'send_sms': {
            return await this.handleSendSms(request.params.arguments as SendSmsParams);
          }
          case 'send_bulk_sms': {
            return await this.handleSendBulkSms(request.params.arguments as SendBulkSmsParams);
          }
          case 'send_verification_code': {
            return await this.handleSendVerification(request.params.arguments as VerificationParams);
          }
          case 'check_credit': {
            return await this.handleCheckCredit();
          }
          default:
            throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
        }
      } catch (error: any) {
        if (axios.isAxiosError(error)) {
          const axiosError = error as AxiosError;
          const statusCode = axiosError.response?.status;
          const responseData = axiosError.response?.data;

          return {
            content: [
              {
                type: 'text',
                text: `SMS.ir API error (${statusCode}): ${JSON.stringify(responseData)}`,
              },
            ],
            isError: true,
          };
        }

        return {
          content: [
            {
              type: 'text',
              text: `Unexpected error: ${error.message || JSON.stringify(error)}`,
            },
          ],
          isError: true,
        };
      }
    });
  }

  private async handleSendSms(params: SendSmsParams) {
    const response = await this.axiosInstance.post('/send', {
      mobile: params.mobile,
      message: params.message,
      lineNumber: params.lineNumber,
      sendDateTime: params.sendDateTime,
    });

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(response.data, null, 2),
        },
      ],
    };
  }

  private async handleSendBulkSms(params: SendBulkSmsParams) {
    const response = await this.axiosInstance.post('/send/bulk', {
      lineNumber: params.lineNumber,
      messageText: params.messageText,
      mobiles: params.mobiles,
      sendDateTime: params.sendDateTime,
    });

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(response.data, null, 2),
        },
      ],
    };
  }

  private async handleSendVerification(params: VerificationParams) {
    const response = await this.axiosInstance.post('/send/verify', {
      mobile: params.mobile,
      templateId: params.templateId,
      parameters: params.parameters,
    });

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(response.data, null, 2),
        },
      ],
    };
  }

  private async handleCheckCredit() {
    const response = await this.axiosInstance.get('/credit');
    
    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(response.data, null, 2),
        },
      ],
    };
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('SMS.ir MCP server running on stdio');
  }
}

// Initialize and run the server
const main = async () => {
  try {
    // Dynamically import the SDK
    const sdk = await import(MCP_SDK);
    const { Server, StdioServerTransport, CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } = sdk;
    
    // Extend the SmsIrServer class with the imported SDK
    Object.assign(SmsIrServer.prototype, { Server, StdioServerTransport, CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError });
    
    // Get API key from environment variables
    const API_KEY = process.env.SMS_IR_API_KEY;
    if (!API_KEY) {
      throw new Error('SMS_IR_API_KEY environment variable is required');
    }
    
    const server = new SmsIrServer(API_KEY);
    await server.run();
  } catch (error) {
    console.error('Failed to start SMS.ir MCP server:', error);
    process.exit(1);
  }
};

main();