<:Head>
  <title>Add an Instance</title>
</:Head>

<Layout page='settings'>
  <SettingsLayout page='settings/instances/add' label="Add an Instance">
    <h1 id="add-an-instance-h1">Add an Instance</h1>

    <LoadingMask show="{{loading}}"/>

    {{#if $isUserLoggedIn}}
    <p>Connect to an instance to log in.</p>
    {{else}}
    <p>Log in to an instance to start using Pinafore.</p>
    {{/if}}

    <form class="add-new-instance" on:submit='onSubmit(event)' aria-labelledby="add-an-instance-h1">

      <label for="instanceInput">Instance:</label>
      <input class="new-instance-input" type="text" id="instanceInput"
             bind:value='$instanceNameInSearch' placeholder='' required
      >
      <button class="primary" type="submit" id="submitButton" disabled="{{!$instanceNameInSearch}}">Add instance</button>

      {{#if error}}
      <div class="form-error" role="alert">
        Error: {{error}}
      </div>
      {{/if}}

    </form>

    {{#if !$isUserLoggedIn}}
    <p>Don't have an instance? <a rel="noopener" target="_blank" href="https://joinmastodon.org">Join Mastodon!</a></p>
    {{/if}}
  </SettingsLayout>
</Layout>
<style>
  .form-error {
    border: 2px solid red;
    border-radius: 2px;
    padding: 10px;
    font-size: 1.3em;
    margin: 5px;
    background-color: var(--main-bg);
  }
  input.new-instance-input {
    min-width: 50%;
    max-width: 100%;
  }

  form.add-new-instance {
    background: var(--form-bg);
    padding: 5px 10px 15px;
    margin: 20px auto;
    border: 1px solid var(--form-border);
    border-radius: 4px;
  }

  form.add-new-instance label, form.add-new-instance input, form.add-new-instance button {
    display: block;
    margin: 20px 5px;
  }

  @media (max-width: 767px) {
    input.new-instance-input {
      max-width: 80%;
    }
  }
</style>
<script>
  import Layout from '../../_components/Layout.html';
  import SettingsLayout from '../_components/SettingsLayout.html'
  import { registerApplication, generateAuthLink, getAccessTokenFromAuthCode } from '../../_utils/mastodon/oauth'
  import { getVerifyCredentials } from '../../_utils/mastodon/user'
  import { getInstanceInfo } from '../../_utils/mastodon/instance'
  import { store } from '../../_utils/store'
  import { goto } from 'sapper/runtime.js'
  import { switchToTheme } from '../../_utils/themeEngine'
  import LoadingMask from '../../_components/LoadingMask'
  import { database } from '../../_utils/database/database'

  const REDIRECT_URI = (typeof location !== 'undefined' ?
      location.origin : 'https://pinafore.social') + '/settings/instances/add'

  export default {
    async oncreate () {
      let params = new URLSearchParams(location.search)
      if (params.has('code')) {
        this.onReceivedOauthCode(params.get('code'))
      }
      this.store.observe('instanceNameInSearch', () => {
        this.set({error: false})
      })
    },
    components: {
      Layout,
      SettingsLayout,
      LoadingMask
    },
    store: () => store,
    methods: {
      onSubmit: async function(event) {
        event.preventDefault()
        this.set({loading: true})
        try {
          await this.redirectToOauth()
        } catch (err) {
          console.error(err)
          let error = `${err.message || err.name}. ` +
            (navigator.onLine ?
              `Is this a valid Mastodon instance?` :
              `Are you offline?`)
          this.set({error: error})
        } finally {
          this.set({loading: false})
        }
      },
      redirectToOauth: async function() {
        let instanceName = this.store.get('instanceNameInSearch')
        let loggedInInstances = this.store.get('loggedInInstances')
        instanceName = instanceName.replace(/^https?:\/\//, '').replace('/$', '')
        if (Object.keys(loggedInInstances).includes(instanceName)) {
          this.set({error: `You've already logged in to ${instanceName}`})
          return
        }
        let registrationPromise = registerApplication(instanceName, REDIRECT_URI)
        let instanceInfo = await getInstanceInfo(instanceName)
        await database.setInstanceInfo(instanceName, instanceInfo) // cache for later
        let instanceData = await registrationPromise
        this.store.set({
          currentRegisteredInstanceName: instanceName,
          currentRegisteredInstance: instanceData
        })
        this.store.save()
        let oauthUrl = generateAuthLink(
          instanceName,
          instanceData.client_id,
          REDIRECT_URI
        )
        document.location.href = oauthUrl
      },
      onReceivedOauthCode: async function(code) {
        try {
          this.set({loading: true})
          await this.registerNewInstance(code)
        } catch (err) {
          this.set({error: `${err.message || err.name}. Failed to connect to instance.`})
        } finally {
          this.set({loading: false})
        }
      },
      registerNewInstance: async function (code) {
        let currentRegisteredInstanceName = this.store.get('currentRegisteredInstanceName')
        let currentRegisteredInstance = this.store.get('currentRegisteredInstance')
        let instanceData = await getAccessTokenFromAuthCode(
          currentRegisteredInstanceName,
          currentRegisteredInstance.client_id,
          currentRegisteredInstance.client_secret,
          code,
          REDIRECT_URI
        )
        let loggedInInstances = this.store.get('loggedInInstances')
        let loggedInInstancesInOrder = this.store.get('loggedInInstancesInOrder')
        let instanceThemes = this.store.get('instanceThemes')
        instanceThemes[currentRegisteredInstanceName] = 'default'
        loggedInInstances[currentRegisteredInstanceName] = instanceData
        if (!loggedInInstancesInOrder.includes(currentRegisteredInstanceName)) {
          loggedInInstancesInOrder.push(currentRegisteredInstanceName)
        }
        this.store.set({
          instanceNameInSearch: '',
          currentRegisteredInstanceName: null,
          currentRegisteredInstance: null,
          loggedInInstances: loggedInInstances,
          currentInstance: currentRegisteredInstanceName,
          loggedInInstancesInOrder: loggedInInstancesInOrder,
          instanceThemes: instanceThemes
        })
        this.store.save()
        switchToTheme('default')
        // fire off request for account so it's cached
        getVerifyCredentials(currentRegisteredInstanceName, instanceData.access_token).then(verifyCredentials => {
          database.setInstanceVerifyCredentials(currentRegisteredInstanceName, verifyCredentials)
        })
        goto('/')
      }
    }
  }
</script>