/*
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 { Readable } from "stream";
import { randomBytes } from "crypto";

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 cors from 'cors';
import bodyParser from 'body-parser';
import swaggerJsDoc from 'swagger-jsdoc';

// routes
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 { GeminiRoutes } from './routes/googleGemini.js';

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

function generateAkenoKey() {
    const randomString = randomBytes(24).toString("base64").replace(/[^a-zA-Z0-9]/g, "");
    return `akeno_${randomString}`;
}

app.use(async (req, res, next) => {
    await CheckMilWares.handle(req, res, next);
});
app.use("/api/v1/", apiLimiter);
app.disable("x-powered-by");
app.disable("link")
app.use(cors({
    origin: '*',
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization']
}));

app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);

app.use(express.static('public'));

// routes
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);

const specs = swaggerJsDoc(swaggerOptions);

app.delete("/api/v1/delete-key", 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("/api/v1/test", authenticateApiKey, apiLimiter, async (req, res) => {
  res.json({ message: "access key" });
})

app.post("/api/v1/revoked-key", 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" });
        }

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

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

        const newKey = generateAkenoKey();

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

        if (result.modifiedCount > 0) {
            res.json({
              message: "API key successfully revoked and regenerated",
              apiKey: newKey,
              createdAt: new Date(),
              owner: userIdNumber
            });
        } 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/generate-key', async (req, res) => {
  const dbClient = new Database("AkenoXJs");
  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;
    
    if (isNaN(userIdNumber)) {
      return res.status(400).json({ error: "Invalid or missing user_id" });
    }
    const existingUser = await collection.findOne({ owner: userIdNumber });

    if (existingUser) {
      return res.status(200).json({
        apiKey: existingUser.key,
        createdAt: existingUser.createdAt,
        owner: existingUser.owner
      });
    }
    const userDocument = {
      key: newKey,
      createdAt: new Date(),
      owner: userIdNumber
    };
    if (email) {
      userDocument.email = email;
    }
    await collection.insertOne(userDocument);
    res.json({ apiKey: newKey });
  } 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.get("/scraper/read", ( req, res ) => {
  res.sendFile(path.join(__dirname + "/public/docs.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);