const convict = require('convict');
const convict_format_with_validator = require('convict-format-with-validator');
const { tmpdir } = require('os');
const path = require('path');
const { randomBytes } = require('crypto');

convict.addFormats(convict_format_with_validator);

convict.addFormat({
  name: 'positive-int-array',
  coerce: ints => {
    // can take: int[] | string[] | string (csv), returns -> int[]
    const ints_arr = Array.isArray(ints) ? ints : ints.trim().split(',');
    return ints_arr.map(int =>
      typeof int === 'number'
        ? int
        : parseInt(int.replace(/['"]+/g, '').trim(), 10)
    );
  },
  validate: ints => {
    // takes: int[], errors if any NaNs, negatives, or floats present
    for (const int of ints) {
      if (typeof int !== 'number' || isNaN(int) || int < 0 || int % 1 > 0)
        throw new Error('must be a comma-separated list of positive integers');
    }
  }
});

const conf = convict({
  s3_bucket: {
    format: String,
    default: '',
    env: 'S3_BUCKET'
  },
  s3_endpoint: {
    format: String,
    default: '',
    env: 'S3_ENDPOINT'
  },
  s3_use_path_style_endpoint: {
    format: Boolean,
    default: false,
    env: 'S3_USE_PATH_STYLE_ENDPOINT'
  },
  gcs_bucket: {
    format: String,
    default: '',
    env: 'GCS_BUCKET'
  },
  expire_times_seconds: {
    format: 'positive-int-array',
    default: [300, 3600, 86400, 604800],
    env: 'EXPIRE_TIMES_SECONDS'
  },
  default_expire_seconds: {
    format: Number,
    default: 86400,
    env: 'DEFAULT_EXPIRE_SECONDS'
  },
  max_expire_seconds: {
    format: Number,
    default: 86400 * 7,
    env: 'MAX_EXPIRE_SECONDS'
  },
  download_counts: {
    format: 'positive-int-array',
    default: [1, 2, 3, 4, 5, 20, 50, 100],
    env: 'DOWNLOAD_COUNTS'
  },
  default_downloads: {
    format: Number,
    default: 1,
    env: 'DEFAULT_DOWNLOADS'
  },
  max_downloads: {
    format: Number,
    default: 100,
    env: 'MAX_DOWNLOADS'
  },
  max_files_per_archive: {
    format: Number,
    default: 64,
    env: 'MAX_FILES_PER_ARCHIVE'
  },
  max_archives_per_user: {
    format: Number,
    default: 16,
    env: 'MAX_ARCHIVES_PER_USER'
  },
  redis_host: {
    format: String,
    default: 'localhost',
    env: 'REDIS_HOST'
  },
  redis_port: {
    format: Number,
    default: 6379,
    env: 'REDIS_PORT'
  },
  redis_user: {
    format: String,
    default: '',
    env: 'REDIS_USER'
  },
  redis_password: {
    format: String,
    default: '',
    env: 'REDIS_PASSWORD'
  },
  redis_db: {
    format: String,
    default: '',
    env: 'REDIS_DB'
  },
  redis_event_expire: {
    format: Boolean,
    default: false,
    env: 'REDIS_EVENT_EXPIRE'
  },
  redis_retry_time: {
    format: Number,
    default: 10000,
    env: 'REDIS_RETRY_TIME'
  },
  redis_retry_delay: {
    format: Number,
    default: 500,
    env: 'REDIS_RETRY_DELAY'
  },
  listen_address: {
    format: 'ipaddress',
    default: '0.0.0.0',
    env: 'IP_ADDRESS'
  },
  listen_port: {
    format: 'port',
    default: 1443,
    arg: 'port',
    env: 'PORT'
  },
  sentry_id: {
    format: String,
    default: '',
    env: 'SENTRY_CLIENT'
  },
  sentry_dsn: {
    format: String,
    default: '',
    env: 'SENTRY_DSN'
  },
  env: {
    format: ['production', 'development', 'test'],
    default: 'development',
    env: 'NODE_ENV'
  },
  max_file_size: {
    format: Number,
    default: 1024 * 1024 * 1024 * 2.5,
    env: 'MAX_FILE_SIZE'
  },
  l10n_dev: {
    format: Boolean,
    default: false,
    env: 'L10N_DEV'
  },
  base_url: {
    format: 'url',
    default: 'https://send.example.com',
    env: 'BASE_URL'
  },
  custom_title: {
    format: String,
    default: 'Send',
    env: 'CUSTOM_TITLE'
  },
  custom_description: {
    format: String,
    default: 'Encrypt and send files with a link that automatically expires to ensure your important documents don’t stay online forever.',
    env: 'CUSTOM_DESCRIPTION'
  },
  detect_base_url: {
    format: Boolean,
    default: false,
    env: 'DETECT_BASE_URL'
  },
  file_dir: {
    format: 'String',
    default: `${tmpdir()}${path.sep}send-${randomBytes(4).toString('hex')}`,
    env: 'FILE_DIR'
  },
  fxa_url: {
    format: 'url',
    default: 'https://send-fxa.dev.lcip.org',
    env: 'FXA_URL'
  },
  fxa_client_id: {
    format: String,
    default: '', // disabled
    env: 'FXA_CLIENT_ID'
  },
  fxa_key_scope: {
    format: String,
    default: 'https://identity.mozilla.com/apps/send',
    env: 'FXA_KEY_SCOPE'
  },
  fxa_csp_oauth_url: {
    format: String,
    default: '',
    env: 'FXA_CSP_OAUTH_URL'
  },
  fxa_csp_content_url: {
    format: String,
    default: '',
    env: 'FXA_CSP_CONTENT_URL'
  },
  fxa_csp_profile_url: {
    format: String,
    default: '',
    env: 'FXA_CSP_PROFILE_URL'
  },
  fxa_csp_profileimage_url: {
    format: String,
    default: '',
    env: 'FXA_CSP_PROFILEIMAGE_URL'
  },
  survey_url: {
    format: String,
    default: '',
    env: 'SURVEY_URL'
  },
  ip_db: {
    format: String,
    default: '',
    env: 'IP_DB'
  },
  footer_donate_url: {
    format: String,
    default: '',
    env: 'SEND_FOOTER_DONATE_URL'
  },
  footer_cli_url: {
    format: String,
    default: 'https://github.com/timvisee/ffsend',
    env: 'SEND_FOOTER_CLI_URL'
  },
  footer_dmca_url: {
    format: String,
    default: '',
    env: 'SEND_FOOTER_DMCA_URL'
  },
  footer_source_url: {
    format: String,
    default: 'https://github.com/timvisee/send',
    env: 'SEND_FOOTER_SOURCE_URL'
  },
  custom_footer_text: {
    format: String,
    default: '',
    env: 'CUSTOM_FOOTER_TEXT'
  },
  custom_footer_url: {
    format: String,
    default: '',
    env: 'CUSTOM_FOOTER_URL'
  },
  ui_color_primary: {
    format: String,
    default: '#0a84ff',
    env: 'UI_COLOR_PRIMARY'
  },
  ui_color_accent: {
    format: String,
    default: '#003eaa',
    env: 'UI_COLOR_ACCENT'
  },
  custom_locale: {
    format: String,
    default: '',
    env: 'CUSTOM_LOCALE'
  },
  ui_custom_assets: {
    android_chrome_192px: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_ANDROID_CHROME_192PX'
    },
    android_chrome_512px: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_ANDROID_CHROME_512PX'
    },
    apple_touch_icon: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_APPLE_TOUCH_ICON'
    },
    favicon_16px: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_FAVICON_16PX'
    },
    favicon_32px: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_FAVICON_32PX'
    },
    icon: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_ICON'
    },
    safari_pinned_tab: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_SAFARI_PINNED_TAB'
    },
    facebook: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_FACEBOOK'
    },
    twitter: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_TWITTER'
    },
    wordmark: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_ASSETS_WORDMARK'
    },
    custom_css: {
      format: String,
      default: '',
      env: 'UI_CUSTOM_CSS'
    }
  }
});

// Perform validation
conf.validate({ allowed: 'strict' });

const props = conf.getProperties();

const deriveBaseUrl = req => {
  if (!props.detect_base_url) {
    return props.base_url;
  }

  const protocol = req.secure ? 'https://' : 'http://';
  return `${protocol}${req.headers.host}`;
};

module.exports = {
  ...props,
  deriveBaseUrl
};
