import {
  KnapsackFile,
  KsCloudConfig,
  KsCloudSaveBody,
  KsFileSaver,
  PERMISSIONS,
} from '@knapsack/core';
import { GenericResponse } from '@knapsack/core/types';
import urlJoin from 'url-join';
import { isAbsolute, join, relative } from 'path';
import { error as logError } from '../cli/log';

export class KsCloudConnect {
  cloudConfig: KsCloudConfig;

  constructor(cloudConfig: KsCloudConfig) {
    this.cloudConfig = cloudConfig;
    // this.saveFilesToCloud = this.saveFilesToCloud.bind(this);
  }

  saveFilesToCloud: KsFileSaver = async ({
    files,
    title = 'New changes',
    message,
    user,
  }) => {
    if (!this.cloudConfig) {
      return {
        ok: false,
        message: 'No "cloud" in your "knapsack.config.js"',
      };
    }

    if (!user?.role?.permissions?.includes(PERMISSIONS.WRITE)) {
      return {
        ok: false,
        message: `Your user does not have write permission, sorry.`,
      };
    }

    const {
      // apiKey,
      apiBase,
      repoRoot,
      repoName,
      repoOwner,
      baseBranch = 'master',
      alterSavedFilePath,
    } = this.cloudConfig;

    const repo = `${repoOwner}/${repoName}`;
    // @todo re-enable repo access check. disabled b/c adding users to user involved manual api call.
    // if (!user.ksRepoAccess.includes(repo)) {
    //   return {
    //     ok: false,
    //     message: `Your user does not have permission to write to the "${repo}" repo, only these: ${user.ksRepoAccess?.join(
    //       ', ',
    //     )}`,
    //   };
    // }

    function prepFilePath(filePath: string): string {
      const fullPath = isAbsolute(filePath)
        ? filePath
        : join(process.cwd(), filePath);
      return relative(repoRoot, fullPath);
    }

    const body: KsCloudSaveBody = {
      owner: repoOwner,
      repo: repoName,
      baseBranch,
      title: `${title} from ${user.username}`,
      message,
      payload: {
        files: files.map(file => {
          const filePath = alterSavedFilePath
            ? alterSavedFilePath(file.path)
            : prepFilePath(file.path);

          if (typeof filePath !== 'string') {
            console.log(file);

            const msg = `While prepping for file save, this file did not end up as a string, in: "${file.path}", out: "${filePath}".`;
            logError(msg, null, 'cloud');
            throw new Error(msg);
          }

          if (isAbsolute(filePath)) {
            console.log(file);
            const msg = `While prepping for file save, this file did not end up as a relative path, in: "${file.path}", out: "${filePath}".`;
            logError(msg, null, 'cloud');
            throw new Error(msg);
          }
          return {
            ...file,
            path: filePath,
          };
        }),
      },
    };

    // console.log('Sending save request to Knapsack Cloud...');
    // console.log('files paths:');
    // console.log(body.payload.files.map(file => file.path).join('\n'));
    const endpoint = urlJoin(apiBase, 'api/save');
    return fetch(endpoint, {
      method: 'POST',
      body: JSON.stringify(body),
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        // can't add auth just yet, cloud api uses it if present to attempt to authenticate as GitHub user (then falls back to GitHub app); this auth token is currently the AWS Cognito user.
        // Authorization: user.Authorization,
        // 'x-api-key': apiKey,
      },
    })
      .then(res => {
        const { ok, status, statusText } = res;
        // console.log({ ok, status, statusText });
        if (!ok) {
          const result: GenericResponse = {
            ok,
            message: `${status} - ${statusText}`,
          };
          return result;
        }
        return res.json();
      })
      .catch(e => {
        console.error('error saveFilesToCloud');
        console.error(e);
        const result: GenericResponse = {
          ok: false,
          message: `thrown error in saveFilesToCloud: ${e.message}`,
        };
        return result;
      });
  };
}
