import { defineConfig } from 'cypress';
import { Client } from "pg";
import { createServer } from 'http'
import { ZITADELWebhookEvent } from 'cypress/support/types';

const jwt = require('jsonwebtoken');

const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAzi+FFSJL7f5yw4KTwzgMP34ePGycm/M+kT0M7V4Cgx5V3EaD
IvTQKTLfBaEB45zb9LtjIXzDw0rXRoS2hO6th+CYQCz3KCvh09C0IzxZiB2IS3H/
aT+5Bx9EFY+vnAkZjccbyG5YNRvmtOlnvIeIH7qZ0tEwkPfF5GEZNPJPtmy3UGV7
iofdVQS1xRj73+aMw5rvH4D8IdyiAC3VekIbpt0Vj0SUX3DwKtog337BzTiPk3aX
RF0sbFhQoqdJRI8NqgZjCwjq9yfI5tyxYswn+JGzHGdHvW3idODlmwEt5K2pasiR
IWK2OGfq+w0EcltQHabuqEPgZlmhCkRdNfixBwIDAQABAoIBAA9jNoBkRdxmH/R9
Wz+3gBqA9Aq4ZFuzJJk8QCm62V8ltWyyCnliYeKhPEm0QWrWOwghr/1AzW9Wt4g4
wVJcabD5TwODF5L0626eZcM3bsscwR44TMJzEgD5EWC2j3mKqFCPaoBj08tq4KXh
wW8tgjgz+eTk3cYD583qfTIZX1+SzSMBpetTBsssQtGhhOB/xPiuL7hi+fXmV2rh
8mc9X6+wJ5u3zepsyK0vBeEDmurD4ZUIXFrZ0WCB/wNkSW9VKyoH+RC1asQAgqTz
glJ/NPbDJSKGvSBQydoKkqoXx7MVJ8VObFddfgo4dtOoz6YCfUVBHt8qy+E5rz5y
CICjL/kCgYEA9MnHntVVKNXtEFZPo02xgCwS3eG27ZwjYgJ1ZkCHM5BuL4MS7qbr
743/POs1Ctaok0udHl1PFB4uAG0URnmkUnWzcoJYb6Plv03F0LRdsnfuhehfIxLP
nWvxSm5n21H4ytfxm0BWY09JkLDnJZtXrgTILbuqb9Wy6TmAvUaF2YUCgYEA16Ec
ywSaLVdqPaVpsTxi7XpRJAB2Isjp6RffNEecta4S0LL7s/IO3QXDH9SYpgmgCTah
3aXhpT4hIFlpg3eBjVfbOwgqub8DgirnSQyQt99edUtHIK+K8nMdGxz6X6pfTKzK
asSH7qPlt5tz1621vC0ocXSZR7zm99/FgwILwBsCgYBOsP8nJFV4By1qbxSy3qsN
FR4LjiAMSoFlZHzxHhVYkjmZtH1FkwuNuwwuPT6T+WW/1DLyK/Tb9se7A1XdQgV9
LLE/Qn/Dg+C7mvjYmuL0GHHpQkYzNDzh0m2DC/L/Il7kdn8I9anPyxFPHk9wW3vY
SVlAum+T/BLDvuSP9DfbMQKBgCc1j7PG8XYfOB1fj7l/volqPYjrYI/wssAE7Dxo
bTGIJrm2YhiVgmhkXNfT47IFfAlQ2twgBsjyZDmqqIoUWAVonV+9m29NMYkg3g+l
bkdRIa74ckWaRgzSK8+7VDfDFjMuFFyXwhP9z460gLsORkaie4Et75Vg3yrhkNvC
qnpTAoGBAMguDSWBbCewXnHlKGFpm+LH+OIvVKGEhtCSvfZojtNrg/JBeBebSL1n
mmT1cONO+0O5bz7uVaRd3JdnH2JFevY698zFfhVsjVCrm+fz31i5cxAgC39G2Lfl
YkTaa1AFLstnf348ZjuvBN3USUYZo3X3mxnS+uluVuRSGwIKsN0a
-----END RSA PRIVATE KEY-----`

let tokensCache = new Map<string,string>()
let webhookEvents = new Array<ZITADELWebhookEvent>()
let failWebhookEventsCount = 0

export default defineConfig({
  reporter: 'mochawesome',

  reporterOptions: {
    reportDir: 'cypress/results',
    overwrite: false,
    html: true,
    json: true,
  },

  trashAssetsBeforeRuns: false,
  defaultCommandTimeout: 10000,

  env: {
    ORGANIZATION: process.env.CYPRESS_ORGANIZATION || 'zitadel',
    BACKEND_URL: backendUrl(),
    WEBHOOK_HANDLER_PORT: webhookHandlerPort(),
    WEBHOOK_HANDLER_HOST: process.env.CYPRESS_WEBHOOK_HANDLER_HOST || 'localhost',
  },

  e2e: {
    baseUrl: baseUrl(),
    experimentalRunAllSpecs: true,
    setupNodeEvents(on, config) {

      startWebhookEventHandler()

      on('task', {
        safetoken({key, token}) {
          tokensCache.set(key,token);
          return null
        },
        loadtoken({key}): string | null {
          return tokensCache.get(key) || null;
        },
        systemToken(): Promise<string> {
          let iat = Math.floor(Date.now() / 1000);
          let exp = iat + (999*12*30*24*60*60) // ~ 999 years
          return jwt.sign({
            "iss": "cypress",
            "sub": "cypress",
            "aud": backendUrl(),
            "iat": iat,
            "exp": exp
          }, Buffer.from(privateKey, 'ascii').toString('ascii'), { algorithm: 'RS256' })
        },
        async runSQL(statement: string) {
          const client = new Client({
            connectionString: process.env.CYPRESS_DATABASE_CONNECTION_URL || 'postgresql://root@localhost:26257/zitadel'
          });

          return client.connect().then(() => {
            return client.query(statement).then((result) => {
              return client.end().then(() => {
                return result
              })
            })
          })
        },
        resetWebhookEvents() {
          webhookEvents = []
          failWebhookEventsCount = 0
          return null
        },
        handledWebhookEvents(){
          return webhookEvents
        },
        failWebhookEvents(count: number){
          failWebhookEventsCount = count
          return null
        }
      })
    },
  },
});

function baseUrl(){
  return process.env.CYPRESS_BASE_URL || 'http://localhost:8080/ui/console'
}

function backendUrl(){
  return process.env.CYPRESS_BACKEND_URL || baseUrl().replace("/ui/console", "")
}

function webhookHandlerPort() {
  return process.env.CYPRESS_WEBHOOK_HANDLER_PORT || '8900'
}

function startWebhookEventHandler() {
  const port = webhookHandlerPort()
  const server = createServer((req, res) => {
    const chunks = [];
    req.on("data", (chunk) => {
      chunks.push(chunk);
    });
    const sendStatus = failWebhookEventsCount ? 500 : 200
    req.on("end", () => {
      webhookEvents.push({
        sentStatus: sendStatus,
        payload: JSON.parse(Buffer.concat(chunks).toString())
      });
    });
    if (failWebhookEventsCount > 0){
      failWebhookEventsCount--
    }
    res.writeHead(sendStatus);
    res.end()
  });

  server.listen(port, () => {
    console.log(`Server is running on http://:${port}`);
  });
}