/*
Credits @xpushz on telegram 
Copyright 2017-2025 (c) Randy W @xtdevs, @xtsea on telegram

from : https://github.com/TeamKillerX
Channel : @RendyProjects
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

import express from 'express';
const app = express();

import * as swaggerUi from 'swagger-ui-express';
import * as cheerio from 'cheerio';
import * as lifestyle from './startup/lifestyle.js';
import * as uuid from 'uuid';

import { Database } from './database/database.js'
import { ApiKey } from './models.js';
import { Readable } from "stream";
import { randomBytes } from "crypto";
import { AkenoaiJs } from "akenoaijs";

import { 
  CheckMilWare,
  authenticateApiKey,
  apiLimiter
} from './middleware/midware.js';

import { setup, serve } from './swagger.js';
import { swaggerOptions } from './settingOptions.js';
import path from "path";
import sharp from "sharp";
import bodyParser from 'body-parser';
import swaggerJsDoc from 'swagger-jsdoc';
import helmet from "helmet";

// routes
import { TrendingNewRoutes } from './plugins/trendings.js';
import { GempaRoutes } from './plugins/gempa.js';
import { FluxRoutes } from './plugins/fluxai.js';
import { GptRoutes } from './plugins/gptold.js';
import { HentaiRoutes } from './plugins/hentai.js';
import { TebakRoutes } from './plugins/tebak.js';
import { CopilotRoutes } from './plugins/copilot.js';
import { CarbonRoutes } from './plugins/carbon.js';
import { UnblockIpRoutes } from './plugins/unblockip.js';
import { AntibanRoutes } from './plugins/antiban.js';
import { AllDlRoutes } from './plugins/alldownloader.js';
import { GeminiRoutes } from './routes/googleGemini.js';

const __dirname = path.resolve();
const CheckMilWares = new CheckMilWare();
const myUUID = uuid.v4();

function _0x8e5f(){const _0x47a684=['21328MwnItu','akeno_','2HGYaRq','7539MDsoUT','239924nJVgmv','67736vpCrKx','7007630HuiUXg','620826tHyNgs','978pHDPNY','153GWQrSV','1344810LrohVJ'];_0x8e5f=function(){return _0x47a684;};return _0x8e5f();}(function(_0x2cc85e,_0x5b8aeb){const _0x30a48=_0x2eb9,_0x508eac=_0x2cc85e();while(!![]){try{const _0x401ae4=parseInt(_0x30a48(0x1b1))/0x1*(parseInt(_0x30a48(0x1b3))/0x2)+-parseInt(_0x30a48(0x1b6))/0x3+parseInt(_0x30a48(0x1af))/0x4+-parseInt(_0x30a48(0x1b9))/0x5+-parseInt(_0x30a48(0x1b7))/0x6*(parseInt(_0x30a48(0x1b2))/0x7)+-parseInt(_0x30a48(0x1b4))/0x8*(parseInt(_0x30a48(0x1b8))/0x9)+parseInt(_0x30a48(0x1b5))/0xa;if(_0x401ae4===_0x5b8aeb)break;else _0x508eac['push'](_0x508eac['shift']());}catch(_0x43caee){_0x508eac['push'](_0x508eac['shift']());}}}(_0x8e5f,0x24c61));function _0x2eb9(_0x71c9ef,_0x40f517){const _0x8e5f80=_0x8e5f();return _0x2eb9=function(_0x2eb9aa,_0xe433fa){_0x2eb9aa=_0x2eb9aa-0x1af;let _0x4300be=_0x8e5f80[_0x2eb9aa];return _0x4300be;},_0x2eb9(_0x71c9ef,_0x40f517);}function generateAkenoKey(){const _0x5cad5d=_0x2eb9,_0x399302=randomBytes(0x18)['toString']('base64')['replace'](/[^a-zA-Z0-9]/g,'');return _0x5cad5d(0x1b0)+_0x399302;}

app.use(async (req, res, next) => {
    await CheckMilWares.handle(req, res, next);
});
// app.use(helmet({ dnsPrefetchControl: false }));

app.use("/api/v1/", apiLimiter);
app.use(bodyParser.json());
app.use(express.static('public'));
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);
app.disable("x-powered-by");
app.disable("link")


// routes
app.use(TrendingNewRoutes);
app.use(GeminiRoutes);
app.use(FluxRoutes);
app.use(GptRoutes);
app.use(HentaiRoutes);
app.use(TebakRoutes);
app.use(GempaRoutes);
app.use(CopilotRoutes);
app.use(UnblockIpRoutes);
app.use(CarbonRoutes);
app.use(AntibanRoutes);
app.use(AllDlRoutes);

const specs = swaggerJsDoc(swaggerOptions);

const AllJsonReques = {
  "AkenoXAPI": {
    "akenox_date": new Date(),
    "developer": "@xpushz",
    "language": "JS && Python",
    "cybersecurity": true,
    "source_link": "https://github.com/TeamKillerX/akenoai-lib",
    "ai": {
      "endpoint": "ai/google-gemini",
      "params": "query",
      "method": "GET",
      "headers": "x-api-key",
      "part2": {
        "endpoint": "ai/copilot2-trip",
        "params": "q",
        "method": "GET",
        "headers": "x-api-key",
      },
      "part3": {
        "endpoint": "ai/gpt-old",
        "params": "query",
        "method": "GET",
        "headers": "x-api-key",
      },
    },
    "flux": {
      "endpoint": "flux/flux-ai",
      "body": "query",
      "method": "POST",
      "headers": "x-api-key",
    },
  },
}

app.get("/api/v1/json/all", async (req, res) => {
  res.json(AllJsonReques);
});

app.get('/broadcast-user', async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");
    try {
        const result = await collection.find({}).toArray();
        let userIds = [];
        let storage_dict = {};
        for (const data of result) {
          if (data.owner !== undefined) {
            storage_dict[data.owner] = data.key;
            userIds.push(data.owner);
          }
        }
      res.json({ user_id: userIds, count: userIds.length });
      // console.log(storage_dict);
    } catch (error) {
        console.error("Failed to get data from DB: " + error);
        res.status(500).send("Error fetching data from database.");
    }
});

app.post('/webhook', (req, res) => {
    console.log('Received webhook:', req.body);
    res.status(200).send('Webhook received');
});

app.post("/api/v1/debug/connect", async (req, res) => {
  const dbClient = new Database("AkenoXJs");
  const collection = dbClient.collection("api_keys");

  try {
    const userIdString = req.query.user_id;
    const apiKeyDev = req.query.api_key;
    const userIdNumber = Number(userIdString);

    if (!apiKeyDev || isNaN(userIdNumber) || userIdNumber === 0) {
      return res.status(400).json({ error: "Invalid user_id or API key" });
    }
    const existingUser = await collection.findOne({
      owner: userIdNumber,
      key: apiKeyDev,
    });

    if (!existingUser) {
      return res.status(200).json({
        message: "API key disconnected",
        is_connect: false,
      });
    }

    return res.status(200).json({
      message: "Connected successfully",
      is_connect: true,
      owner: userIdNumber,
      key: apiKeyDev,
    });
  } catch (error) {
    res.status(500).json({ error: `Failed: ${error.message}` });
  }
});

app.delete("/api/v1/key/api-key-delete", authenticateApiKey, apiLimiter, async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");

    try {
        const userIdString = req.query.user_id;
        const userIdNumber = Number(userIdString);

        if (isNaN(userIdNumber) || userIdNumber === 0) {
            return res.status(400).json({ error: "Invalid user_id" });
        }

        if (userIdNumber === 6477856957) {
            return res.status(400).json({ error: "Sorry, only the developer can perform this action." });
        }

        const deleteResult = await collection.deleteMany({ owner: userIdNumber });
        const deleteResultTwo = await ApiKey.deleteMany({ owner: userIdNumber });

        if (deleteResult.deletedCount > 0 || deleteResultTwo.deletedCount > 0) {
            return res.status(200).json({
                message: "API key(s) successfully deleted",
                owner: userIdNumber
            });
        } else {
            return res.status(404).json({ message: "No API keys found for this user" });
        }

    } catch (err) {
        res.status(500).json({ error: `Key deletion failed: ${err.message}` });
    }
});

app.delete("/api/v1/delete-key", authenticateApiKey, apiLimiter, async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");
    const apiKey = req.query.api_key;

    if (!apiKey) {
        return res.status(400).json({ error: "Missing 'api_key' parameter" });
    }

    try {
        const DocsKey = await collection.deleteOne({ key: apiKey });

        if (DocsKey.deletedCount > 0) {
            res.json({ message: "API key has been successfully deleted" });
        } else {
            res.status(404).json({ message: "API key not found" });
        }
    } catch (err) {
        res.status(500).json({ error: `Key deletion failed: ${err.message}` });
    }
});

app.get("/runtime", async (req, res) => {
  res.send("Running lifetime");
})

app.post("/api/v2/key/upgrade-key", authenticateApiKey, apiLimiter, async (req, res) => {
  try {
    const dbClient = new Database("AkenoXJs");
    const bannedCollection = dbClient.collection("banned_users");
    const userIdNumber = Number(req.query.user_id);
    const expire_number = Number(req.query.expire) || 0;

    if (isNaN(userIdNumber) || userIdNumber === 0) {
      return res.status(400).json({ error: "Invalid or missing user_id" });
    }

    const existingUser = await ApiKey.findOne({ owner: userIdNumber });

    const isBanned = await bannedCollection.findOne({ user_id: userIdNumber });
    if (isBanned) {
      return res.status(200).json({ message: "You are permanently banned from creating API keys", is_deleted: true });
    }

    if (!existingUser) {
      return res.status(404).json({ error: "API key expired and deleted. Generate a new key." });
    }

    const expirationDate = new Date();
    expirationDate.setDate(expirationDate.getDate() + expire_number);

    existingUser.expiresAt = expirationDate;
    existingUser.type = "premium";
    existingUser.is_expired = false;
    
    await existingUser.save();
    res.json({
      apiKey: existingUser.key,
      createdAt: existingUser.createdAt,
      expiresAt: expirationDate,
      owner: userIdNumber,
      type: "premium"
    });
  } catch (error) {
    res.status(500).json({ error: `Key upgrade failed: ${error.message}` });
  }
});

app.post('/api/v2/key/generate-key', authenticateApiKey, apiLimiter, async (req, res) => {
  try {
    const newKey = generateAkenoKey();
    const userIdNumber = Number(req.query.user_id);
    const email = req.query.email;

    if (isNaN(userIdNumber)) {
      return res.status(400).json({ error: "Invalid or missing user_id" });
    }

    const existingUser = await ApiKey.findOne({ owner: userIdNumber });
    if (existingUser) {
      return res.status(200).json({
        apiKey: existingUser.key,
        createdAt: existingUser.createdAt,
        is_banned: existingUser.is_banned || false,
        expiresAt: existingUser.expiresAt,
        owner: existingUser.owner,
        type: existingUser.type
      });
    }

    const expirationDate = new Date();
    expirationDate.setDate(expirationDate.getDate() + 30);

    const userDocument = new ApiKey({
      key: newKey,
      owner: userIdNumber,
      createdAt: new Date(),
      expiresAt: expirationDate,
      is_expired: false,
      type: "premium",
      is_banned: false,
      email: email || null
    });
    await userDocument.save();
    res.json({ apiKey: newKey, createdAt: new Date(), expiresAt: expirationDate, owner: userIdNumber, type: "premium" });
  } catch (err) {
    res.status(500).json({ error: `Key generation failed: ${err.message}` });
  }
});

app.post("/api/v1/key/revoked-key", authenticateApiKey, apiLimiter, async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");
    const bannedCollection = dbClient.collection("banned_users");

    try {
        const userIdString = req.query.user_id;
        const userIdNumber = Number(userIdString);
        const username = req.query.username;

        if (isNaN(userIdNumber)) {
            return res.status(400).json({ error: "Invalid or missing user_id" });
        }

        const isBanned = await bannedCollection.findOne({ user_id: userIdNumber });
        if (isBanned) {
          return res.status(200).json({ message: "You are permanently banned from creating API keys", is_deleted: true });
        }
  
        const existingUser = await collection.findOne({ owner: userIdNumber });

        if (!existingUser) {
          return res.status(404).json({ error: "API key not found" });
        }

        if (existingUser) {
          return res.status(200).json({
            is_banned: existingUser.is_banned || false
          });
        }

        const newKey = generateAkenoKey();

        const result = await collection.updateOne(
            { owner: userIdNumber },
            { $set: { key: newKey, createdAt: new Date(), username: username } },
            { upsert: false }
        );

        if (result.modifiedCount > 0) {
            res.json({
              message: "API key successfully revoked and regenerated",
              apiKey: newKey,
              createdAt: new Date(),
              owner: userIdNumber,
              is_deleted: false,
              is_banned: false
            });
        } else {
            res.status(500).json({ error: "Failed to update API key" });
        }

    } catch (err) {
        res.status(500).json({ error: `Key generation failed: ${err.message}` });
    }
});


app.post("/api/v1/key/api-key-unban", authenticateApiKey, apiLimiter, async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");

    try {
        const userIdString = req.query.user_id;
        const userIdNumber = Number(userIdString);

        if (isNaN(userIdNumber)) {
            return res.status(400).json({ error: "Invalid or missing user_id" });
        }

        if (userIdNumber === 0) {
            return res.status(400).json({ error: "Invalid user_id" });
        }

        if (userIdNumber === 6477856957) {
            return res.status(400).json({ error: "sorry only developer" });
        }

        const existingUserTwo  = await ApiKey.findOne({ owner: userIdNumber });
        const existingUser = await collection.findOne({ owner: userIdNumber });

        if (!existingUser || !existingUserTwo) {
            return res.status(404).json({ error: "API key not found" });
        }

        const resultTwo = await ApiKey.updateOne(
          { owner: userIdNumber },
          { $set: { is_banned: false } },
          { upsert: false }
      );

        const result = await collection.updateOne(
            { owner: userIdNumber },
            { $set: { is_banned: false } },
            { upsert: false }
        );

        if (result.matchedCount > 0 && resultTwo.matchedCount > 0) {
            res.json({
              message: "API key successfully unbanned",
              owner: userIdNumber
            });
        } else {
            res.status(500).json({ error: "Failed to unban API key" });
        }

    } catch (err) {
        res.status(500).json({ error: `Key generation failed: ${err.message}` });
    }
});

app.get("/api/v1/key/apikey-banlist", async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");

    try {
        const bannedKeys = await collection.find({ is_banned: true }).toArray();
        if (bannedKeys.length > 0) {
          const bannedOwners = bannedKeys.map(key => key.owner);
          res.json({ 
            owners: bannedOwners,
            is_banned: true 
          });
        } else {
          res.json({ 
            owners: [],
            is_banned: false 
          });
        }
    } catch (err) {
        res.status(500).json({ error: `Failed to fetch banned keys: ${err.message}` });
    }
});

app.post("/api/v1/key/api-key-ban", authenticateApiKey, apiLimiter, async (req, res) => {
    const dbClient = new Database("AkenoXJs");
    const collection = dbClient.collection("api_keys");

    try {
        const userIdString = req.query.user_id;
        const userIdNumber = Number(userIdString);

        if (isNaN(userIdNumber) || userIdNumber === 0) {
            return res.status(400).json({ error: "Invalid user_id" });
        }

        if (userIdNumber === 6477856957) {
            return res.status(400).json({ error: "Sorry, only the developer can perform this action." });
        }
        const existingUser = await collection.findOne({ owner: userIdNumber });
        const existingUserTwo = await ApiKey.findOne({ owner: userIdNumber });

        if (!existingUser && !existingUserTwo) {
            const userDocument = {
              key: "banned",
              createdAt: new Date(),
              owner: userIdNumber,
              type: "free",
              is_banned: true,
              username: null,
            };

            const userDocumentTwo = new ApiKey({
              key: "banned",
              createdAt: new Date(),
              expiresAt: 10,
              owner: userIdNumber,
              type: "premium",
              is_banned: true,
              email: null,
            });

            await collection.insertOne(userDocument);
            await userDocumentTwo.save();

            return res.status(200).json({
              message: "API key successfully banned",
              owner: userIdNumber
            });
        }

        if ((existingUser && existingUser.is_banned) || (existingUserTwo && existingUserTwo.is_banned)) {
            return res.status(200).json({ message: "API key is already banned" });
        }

        const result = await collection.updateOne(
            { owner: userIdNumber },
            { $set: { is_banned: true } },
            { upsert: false }
        );

        const resultTwo = await ApiKey.updateOne(
          { owner: userIdNumber },
          { $set: { is_banned: true } },
          { upsert: false }
        );

        if (result.matchedCount > 0 || resultTwo.matchedCount > 0) {
            return res.status(200).json({
              message: "API key successfully banned",
              owner: userIdNumber
            });
        } else {
            return res.status(500).json({ error: "Failed to ban API key" });
        }

    } catch (err) {
        res.status(500).json({ error: `Key banning failed: ${err.message}` });
    }
});

app.post("/api/v1/key/ban-and-delete", authenticateApiKey, apiLimiter, async (req, res) => {
  const dbClient = new Database("AkenoXJs");
  const bannedCollection = dbClient.collection("banned_users");
  const apiKeysCollection = dbClient.collection("api_keys");

  try {
    const userIdString = req.query.user_id;
    const userIdNumber = Number(userIdString);

    if (isNaN(userIdNumber) || userIdNumber === 0) {
      return res.status(400).json({ error: "Invalid user ID" });
    }

    if (userIdNumber === 6477856957) {
      return res.status(400).json({ error: "Sorry, only the developer can perform this action." });
    }

    await bannedCollection.insertOne({ user_id: userIdNumber, bannedAt: new Date() });
    await apiKeysCollection.deleteMany({ owner: userIdNumber });

    return res.status(200).json({ message: "User permanently banned and API keys deleted\n\nYour account has been permanently deleted, and you are no longer allowed to create an API key\n\nIf you believe this was a mistake or need further assistance, please contact @xpushz." });
  } catch (error) {
    res.status(500).json({ error: `Failed to ban user and delete API keys: ${error.message}` });
  }
});

app.post('/api/v1/key/generate-key', authenticateApiKey, apiLimiter, async (req, res) => {
  const dbClient = new Database("AkenoXJs");
  const bannedCollection = dbClient.collection("banned_users");
  const collection = dbClient.collection('api_keys');
  try {
    const newKey = generateAkenoKey();
    const userIdString = req.query.user_id;
    const userIdNumber = Number(userIdString);
    const email = req.query.email;
    const username = req.query.username;
    
    if (isNaN(userIdNumber)) {
      return res.status(400).json({ error: "Invalid or missing user_id" });
    }

    if (userIdNumber === 0) {
      return res.status(400).json({ error: "Invalid user_id" });
    }

    const isBanned = await bannedCollection.findOne({ user_id: userIdNumber });
    if (isBanned) {
      return res.status(200).json({ message: "You are permanently banned from creating API keys", is_deleted: true });
    }
  
    const existingUser = await collection.findOne({ owner: userIdNumber });

    if (existingUser) {
      return res.status(200).json({
        apiKey: existingUser.key,
        createdAt: existingUser.createdAt,
        is_banned: existingUser.is_banned || false,
        is_deleted: false,
        owner: existingUser.owner
      });
    }

    const userDocument = {
      key: newKey,
      createdAt: new Date(),
      owner: userIdNumber,
      type: "free",
      is_banned: false,
      username: username,
    };
    if (email) {
      userDocument.email = email;
    }
    await collection.insertOne(userDocument);
    res.json({ apiKey: newKey, createdAt: new Date(), owner: userIdNumber });
  } catch (err) {
    res.status(500).json({ error: `Key generation failed: ${err.message}` });
  }
});

app.get("/policy", ( req, res ) => {
  res.sendFile(path.join(__dirname + "/public/policy.html"));
});

app.use(
  '/docs',
  serve,
  setup(specs, {
    customCss: `
      .swagger-ui .topbar { display: none; }
      .swagger-ui .opblock .opblock-summary-path {
        display: inline-block;
        word-break: break-word;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 100%;
      }
    `,
    customCssUrl: "https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.3.0/swagger-ui.min.css",
    customSiteTitle: 'AkenoXJs'
  })
);

app.get('/', (req, res) => {
  res.redirect('https://t.me/RendyProjects');
});

lifestyle.startServer(app);