const http = require('http'); 
const net = require('net');
const { postLog } = require('./logger.js');

const server_main_addr = 'localhost';
const tcpPort = 50011;
const httpPort = 8766;
let ipAddr_server_main = "";
let ipAddr_service_fileTransfer = "";
let port_server_main = 0;
let port_service_fileTransfer = 0;
let openlist_host = '';
let openlist_host_port = 0;
let openlist_username = '';
let openlist_passwd_hash = '';
let openlist_token = '';
let tcpServ_connected = false;
let appinfo_version = '0.0.0.1';
let appinfo_name = 'globalLinkTransfer Module';
let appinfo_buildType = 'debug';
let appinfo_developer = 'MadobiNanami';
let appinfo_buildDate = '2025-11-18';

postLog.info(`${appinfo_name} Ver.${appinfo_version}.${appinfo_buildType}`);
postLog.info(`Developed by ${appinfo_developer} on ${appinfo_buildDate}`);
postLog.info(`Attempting TCP connect to ${server_main_addr}:${tcpPort}`);
const tcpClient = net.createConnection({  // 创建 TCP 客户端
  port: tcpPort,
  host: `${server_main_addr}`,
  family: 4
 }, () => { 
  postLog.info('Connected to TCP server');
  postLog.info('Try to verify connection...');
  tcpClient.write('[Dial] Are you really a SoulSim Main Server?'); // 发送验证请求
});

tcpClient.on('data', (data) => {  // 监听来自服务器的数据
  postLog.debug('Received from TCP server: ' + data.toString(), 1);
  if(tcpServ_connected == false){ // 如果尚未验证连接
    if(data.toString().includes('Yes, I am SoulSim Main Server.')) { // 验证成功
    postLog.info('Connection verified successfully.');
    tcpServ_connected = true;

    // 发送配置 Openlist 请求
    tcpClient.write('[getConfig] <type>openlist</type>');
    return;
  } else {
    postLog.error('Connection verification failed. Closing connection.');  // 验证失败，关闭连接
    tcpClient.end();
    return;
  }
}

  let content = JSON.parse(data.toString());
  if(content.cmdType=='getOneDriveLink'){ // 处理获取 OneDrive 链接请求
    postLog.debug(`Get OneDrive link converte request: ${content.link}`);
    processOneDriveLink(`${content.link}`)
      .then(link => {
        postLog.debug('Processed OneDrive link: ' + link);
        tcpClient.write(JSON.stringify({
          cmdType: 'oneDriveLinkResult',
          link: link
        }));
      })
      .catch(err => {
        postLog.error('Error processing OneDrive link: ' + err);
        tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>error</status> <message>${err}</message>`);
      });
  }
  if(content.cmdType=='configOpenlist'){ // 处理配置 Openlist 请求
    openlist_host = content.openlist_host;
    openlist_host_port = content.openlist_host_port;
    openlist_username = content.openlist_username;
    openlist_passwd_hash = content.openlist_passwd_hash;
    postLog.info('Configured Openlist with host: ' + openlist_host + ', port: ' + openlist_host_port + ', username: ' + openlist_username+', passwd_hash: '+openlist_passwd_hash);
  }
});

tcpClient.on('end', () => { // 监听 TCP 连接关闭事件
  postLog.warn('Disconnected from TCP server');
});

tcpClient.on('error', (err) => { // 监听错误事件
  postLog.fatal('TCP Client Error: ' + err);
});

const server = http.createServer((req, res) => { // 创建 HTTP 服务器
  if (req.method === 'PUT') { // 处理 PUT 请求
    let body = '';
    
    req.on('data', chunk => { // 接收数据块
      body += chunk.toString();
    });
    
    req.on('end', () => { // 数据接收完毕
      try {
        const data = JSON.parse(body);
        postLog.debug('Recev Data: ' + JSON.stringify(data));
        if(data.cmdType=='modifyAddr'){
          if(data.token!=='mM2aF1aQ5dW3hA1cE5jL6hM4tN9jA0'){ // 简单的令牌验证
            res.writeHead(403, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ 
              errorType: '1',
              message: 'Invalid token'
            }));
            return;
          }
          if(data.serverType=='server.main'&&data.ruleName!=='service_SoulSim-Server'){ // 验证规则名称
            res.writeHead(403, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
              errorType: '2',
              message: 'Invalid rule name'
            }));
            return;
          }
          if(data.serverType=='service.fileTransfer'&&data.ruleName!=='service_SoulSim-FileTransfer'){ // 验证规则名称
            res.writeHead(403, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
              errorType: '3',
              message: 'Invalid rule name'
            }));
            return;
          }
          if(data.serverType=='server.main'){ // 更新主服务器地址
            ipAddr_server_main = data.ipAddr;
            port_server_main = data.port;
            postLog.info('Updated main server address to ' + data.ipAddr + ':' + data.port);
          } else if(data.serverType=='service.fileTransfer'){ // 更新文件传输服务地址
            ipAddr_service_fileTransfer = data.ipAddr;
            port_service_fileTransfer = data.port;
            postLog.info('Updated file transfer server address to ' + data.ipAddr + ':' + data.port);
          }
          try {
            tcpClient.write('[modifyAddr] <ipAddr>' + data.ipAddr + '</ipAddr><port>' + data.port + '</port><addrType>' + data.serverType + '</addrType><ruleName>' + data.ruleName + '</ruleName>'); // 发送地址修改请求
            res.writeHead(200, { 'Content-Type': 'application/json' }); // 返回成功响应
            res.end(JSON.stringify({
              errorType: '0',
              message: 'NicePush!'
            }));
          } catch (tcpErr) { // 处理 TCP 写入错误
            postLog.error('Failed to write to TCP server: ' + tcpErr);
            res.writeHead(500, { 'Content-Type': 'application/json' }); // 返回错误响应
            res.end(JSON.stringify({
              errorType: '4',
              message: 'Failed to write to TCP server'
            }));
          }
        }
        if(data.cmdType=='getAddr'){ // 处理获取地址请求
          if(data.addrType=='server.main'){
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
              addrType: 'server.main',
              ipAddr: ipAddr_server_main,
              port: port_server_main
            }));
          } else if(data.addrType=='service.fileTransfer'){
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
              addrType: 'service.fileTransfer',
              ipAddr: ipAddr_service_fileTransfer,
              port: port_service_fileTransfer
            }));
          }
        }
      } catch (error) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Invalid JSON data' }));
      }
    });
    
    req.on('error', () => {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'Internal Server Error' }));
    });
  } else {
    res.writeHead(405, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Method not allowed' }));
  }
});

server.listen(httpPort, () => {
  postLog.info(`Server is running at http://localhost:${httpPort}`);
});

function processOneDriveLink(filePath) {
  return new Promise((resolve, reject) => {
    const body = {
      username: `${openlist_username}`,
      password: `${openlist_passwd_hash}`,
      otp_code: ''
    };
    const bodyString = JSON.stringify(body);

    const options = {
      hostname: openlist_host,
      port: openlist_host_port,
      path: '/api/auth/login/hash',
      method: 'POST',
      headers: {
        'Host': openlist_host + ":" + openlist_host_port,
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'en-US,en;q=0.9',
        'Sec-Ch-Ua-Platform': '"Windows.Server"',
        'Sec-Ch-Ua-Mobile': '?0',
        'User-Agent': 'SoulSim-Server/1.0',
        'Content-Type': 'application/json'
      }
    };

  const req = http.request(options, (res) => {
    const chunks = [];
    res.on('data', (chunk) => {
      chunks.push(chunk);
    });
    res.on('end', () => {
      const data = Buffer.concat(chunks);
      let parsed;
      try{
        parsed = JSON.parse(data);
        // postLog.info('Response data: ' + data.toString());
      } catch (e){
        postLog.error('Failed to convert response to JSON: ' + e);
        tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>error</status> <message>Failed to convert response to JSON: ${e}</message>`);
        postLog.info('Response data: ' + data.toString());
        reject(e);
        return;
      }
      openlist_token = parsed.data.token;
      postLog.info('Got token: ' + openlist_token);
      const options2 = {
        hostname: openlist_host,
        port: openlist_host_port,
        path: '/api/fs/get',
        method: 'POST',
        headers: {
          'Host': openlist_host + ":" + openlist_host_port,
          'Accept': 'application/json, text/plain, */*',
          'Accept-Language': 'en-US,en;q=0.9',
          'Sec-Ch-Ua-Platform': '"Windows"',
          'Sec-Ch-Ua-Mobile': '?0',
          'User-Agent': 'SoulSim-Server/1.0',
          'Content-Type': 'application/json',
          'Authorization': `${openlist_token}`
        }
      }

      const body2 = {
        path: `${filePath}`,
        password: ''
      };
      const body2String = JSON.stringify(body2);

      const req2 = http.request(options2, (res2) => {
        const chunks2 = [];
        res2.on('data', (chunk2) => {
          chunks2.push(chunk2);
        });
        res2.on('end', () => {
          const data2 = Buffer.concat(chunks2);
          try{
            const parsed = JSON.parse(data2);
            postLog.debug('Response data: ' + data2.toString());
            const openlist_getAddr = parsed.data.raw_url;
            tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>success</status> <link>${openlist_getAddr}</link>`);
            // postLog.info(`Get Onedrive Link: ${openlist_getAddr}`);
            resolve(openlist_getAddr);
          } catch(e) {
            postLog.error('Failed to convert response to JSON: ' + e);
            tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>error</status> <message>Failed to convert response to JSON: ${e}</message>`);
            postLog.info('Response data: ' + data2.toString());
            reject(e);
          }
        });
      });

      req2.on('error',(err) =>{
        postLog.error('HTTP request error: ' + err);
        tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>error</status> <message>${err}</message>`);
        reject(err);
      });

      req2.write(body2String);
      req2.end();
  });
});

  req.on('error', (err) => {
    postLog.error('HTTP request error: ' + err);
    tcpClient.write(`[userSet] <method>userGetLink</method> <type>onedrive</type> <status>error</status> <message>${err}</message>`);
    reject(err);
  });

  req.write(bodyString);
  req.end();
  });
}