<script setup>
import { ref, onMounted } from 'vue';
import { service } from './util/http';
import { message, getLang } from './util/locale';
import { store } from './util/store';

const model = ref({
  type: '',
  forward: '',
  index: 0,
  speak: 0,
  welcome: [],
  inputs: [],
  focus: {
    index: 0,
    auto: true,
  },
  submit: false,
  invalid: '',
  forget: false,
  interval: 0,
});
const inputs = { 'in': ['username', 'password'], 'up': ['username', 'nick', 'password', 'repeat'], 'forget': ['username', 'email', 'code', 'newpass', 'repeat'] };

const language = (lang) => {
    store.language = lang;
    localStorage.setItem('language', lang);
    window.location.reload();
};

const type = (i, j) => {
  if (model.value.interval)
    clearInterval(model.value.interval);
  if ((i === 0 && j === 2) || (i === 1 && j === 1)) {
    model.value = {
      type: i === 1 && j === 1 ? 'forget' : (model.value.type === 'up' || model.value.type === 'forget' ? 'in' : 'up'),
      forward: model.value.forward,
      index: 0,
      speak: 0,
      welcome: [],
      inputs: [],
      focus: {
        index: 0,
        auto: true,
      },
      submit: false,
      invalid: '',
      forget: false,
    };
    model.value.interval = setInterval(next, model.value.type === 'in' ? 50 : 100);
  }
};

const next = () => {
  if (model.value.submit || speak())
    return;

  model.value.index++;
  model.value.speak = 0;
};

const speak = () => {
  if (model.value.index === 0) {
    let welcome = message('welcome.' + model.value.type);
    if (model.value.speak > welcome.length)
      return false;

    model.value.welcome = welcome.substring(0, model.value.speak++).split('\n');

    return true;
  }

  let index = model.value.index - 1;
  if (model.value.focus.auto)
    model.value.focus.index = index;
  if (index < inputs[model.value.type].length) {
    let label = message(inputs[model.value.type][index]);
    if (index === 0) {
      label = message('username.' + model.value.type);
    } else if (index === 1 && model.value.type === 'in')
      label += '\n' + message('forget');
    if (model.value.speak > label.length) {
      if (model.value.inputs[index].step === 0)
        model.value.inputs[index].step = 1;

      return model.value.inputs[index].step < 3;
    }

    if (model.value.inputs.length < model.value.index) {
      let input = {
        label: [],
        value: '',
        placeholder: '',
        invalid: '',
        step: 0,
        password: index >= (model.value.type === 'up' ? 2 : (model.value.type === 'in' ? 1 : 3)),
      };
      if (index === 0) {
        if (model.value.type === 'in')
          input.placeholder = message('username-email');
        else if (model.value.type === 'up')
          input.placeholder = message('username.placeholder');
      }
      model.value.inputs.push(input);
    }
    model.value.inputs[index].label = label.substring(0, model.value.speak++).split('\n');

    return true;
  }

  return true;
};

const input = (index) => {
  let value = model.value.inputs[index].value;
  length = value.length;
  if (index === 0) {
    if (model.value.type === 'up') {
      model.value.inputs[index].invalid = length < 4 || length > 15 ? message('username.invalid.up') : '';
      if (!model.value.inputs[index].invalid) {
        service('/user/auth/exists', { uid: value }, data => {
          model.value.inputs[index].step = data ? 2 : 1;
          model.value.inputs[index].invalid = data ? '' : message('username.invalid.up');
        });
      }
    } else {
      model.value.inputs[index].invalid = '';
      model.value.inputs[index].step = 2;
    }
  } else if (index === 1) {
    if (model.value.type === 'up') {
      model.value.inputs[index].invalid = length < 2 || length > 14 ? message('nick.invalid') : '';
      model.value.inputs[index].step = length < 2 || length > 14 ? 1 : 2;
    } else if (model.value.type === 'in') {
      model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
      model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
    } else if (model.value.type === 'forget') {
      let valid = /^(?:\w+\.?-?)*\w+@(?:\w+\.?-?)*\w+$/.test(value);
      model.value.inputs[index].invalid = !valid ? message('email.invalid') : '';
      model.value.inputs[index].step = !valid ? 1 : 2;
    }
  } else if (index === 2) {
    if (model.value.type === 'up') {
      model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
      model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
    } else if (model.value.type === 'forget') {
      model.value.inputs[index].invalid = length === 8 ? '' : message('code.invalid');
      model.value.inputs[index].step = length === 8 ? 2 : 1;
    }
  } else if (index === 3) {
    if (model.value.type === 'up') {
      model.value.inputs[index].invalid = value === model.value.inputs[index - 1].value ? '' : message('repeat.invalid');
      model.value.inputs[index].step = value === model.value.inputs[index - 1].value ? 2 : 1;
    } else if (model.value.type === 'forget') {
      model.value.inputs[index].invalid = length < 7 || length > 20 ? message('password.invalid') : '';
      model.value.inputs[index].step = length < 7 || length > 20 ? 1 : 2;
    }
  } else if (index === 4) {
    model.value.inputs[index].invalid = value === model.value.inputs[index - 1].value ? '' : message('repeat.invalid');
    model.value.inputs[index].step = value === model.value.inputs[index - 1].value ? 2 : 1;
  }
};

const confirm = (index, event, callback) => {
  if (event)
    event.target.blur();
  if (model.value.submit) {
    model.value.focus = { index: model.value.inputs.length + 1, auto: false };

    return;
  }

  if (model.value.type === 'forget' && !callback) {
    if (index === 1) {
      service('/home/forget-email', { uid: model.value.inputs[0].value, email: model.value.inputs[1].value, subject: message('forget.title'), lang: getLang() }, data => {
        model.value.invalid = message(data ? 'code.send' : 'email.failure');
        if (data)
          confirm(index, null, 1);
      });

      return;
    }

    if (index === 2) {
      service('/home/forget-code', { code: model.value.inputs[2].value }, data => {
        if (data)
          confirm(index, null, 1);
        model.value.invalid = data ? '' : message('code.invalid');
      });

      return;
    }
  }

  model.value.focus.auto = true;
  if (model.value.inputs[index].step === 2)
    model.value.inputs[index].step = 3;
  if (model.value.inputs[index].step === 3) {
    model.value.submit = (index === 1 && model.value.type === 'in') || (index === 3 && model.value.type === 'up') || (index === 4 && model.value.type === 'forget');
    if (model.value.submit)
      model.value.focus = { index: index + 1, auto: false };
  }
};

const focus = (index) => {
  model.value.focus = { index, auto: false };
};

const submit = () => {
  if (model.value.type === 'up') {
    service('/user/sign-up', {
      type: '',
      uid: model.value.inputs[0].value,
      nick: model.value.inputs[1].value,
      password: model.value.inputs[2].value,
    }, data => {
      if (data.id) {
        forward();
      } else {
        model.value.invalid = message('sign-up.invalid');
      }
    }, () => model.value.invalid = message('sign-up.invalid'));
  } else if (model.value.type === 'in') {
    service('/user/sign-in', {
      type: '',
      uid: model.value.inputs[0].value,
      password: model.value.inputs[1].value,
    }, data => {
      if (data.id) {
        forward();
      } else {
        model.value.invalid = message('sign-in.invalid');
      }
    }, () => model.value.invalid = message('sign-in.invalid'));
  } else if (model.value.type === 'forget') {
    service('/home/password', { code: model.value.inputs[2].value, password: model.value.inputs[3].value }, data => {
      model.value.forget = data;
      model.value.invalid = message('forget.' + (data ? 'success' : 'failure'));
    });
  }
};

const forward = () => {
  if (model.value.forward === 'parent') {
    window.parent.postMessage({ type: 'sign', value: '' }, '*');
    window.parent.postMessage({ type: 'session', value: localStorage.getItem('photon-session-id')}, '*')
  } else {
    location.href = model.value.forward;
  }
};

onMounted(() => {
  document.title = message('title');
  if (location.search && location.search.indexOf('?') > -1) {
    for (let param of location.search.substring(1).split('&')) {
      if (param.indexOf('type=') === 0) {
        model.value.type = param.substring(5);
      } else if (param.indexOf('forward=') === 0) {
        model.value.forward = decodeURIComponent(param.substring(8));
      }
    }
  }
  if (!model.value.type)
    model.value.type = 'in';
  if (!model.value.forward)
    model.value.forward = '/';
  model.value.interval = setInterval(next, model.value.type === 'in' ? 50 : 100);
  service('/user/sign', {}, data => {
    if (data.id){
      if(model.value.forward === 'parent'){
        window.parent.postMessage({ type: 'sign', value: data.id }, '*');
        window.parent.postMessage({ type: 'session', value: localStorage.getItem('photon-session-id')}, '*')
      }else{
        location.href = model.value.forward;
      }
    }
  });
});
</script>

<template>
  <div class="stars">
    <div v-for="i in 6" class="star"></div>
  </div>
  <div class="sign-in-up">
    <div class="nav">
      <img src="./assets/logo.png" />
      <div class="langs">
        <div @click="language('zh')"><span>中</span></div>
        <div @click="language('en')"><span>En</span></div>
        <div @click="language('jp')"><span>あ</span></div>
      </div>
    </div>
    <div>
      <div class="dialog">
        <div v-for="welcome in model.welcome" class="welcome">{{ welcome }}</div>
        <template v-for="(ip, index) in model.inputs">
          <div class="label">
            <span v-for="(label, li) in ip.label" :class="'label-' + (li === 0 ? '0' : (index + '' + li))"
              @click="type(index, li)">{{ label }}</span>
          </div>
          <div v-if="ip.step > 0" class="input">
            <div v-if="model.focus.index === index" class="arrow">→</div>
            <div v-else-if="model.type === 'up'" class="correct">√</div>
            <input :type="ip.password ? 'password' : 'text'" v-model="model.inputs[index].value"
              :placeholder="model.inputs[index].placeholder" @focus="focus(index)" @input="input(index)"
              @keypress.enter="confirm(index, $event)" />
            <div v-if="model.focus.index === index"
              :class="model.inputs[index].step === 2 ? 'button-valid' : 'button-invalid'" @click="confirm(index)">{{
                message('continue') }}</div>
            <div v-else class="button-empty">{{ message('continue') }}</div>
          </div>
          <div v-else-if="ip.step === 3" class="input">
            <div v-if="model.type === 'up'" class="correct">√</div>
            <div class="value">{{ model.inputs[index].password ? '********' : model.inputs[index].value }}</div>
          </div>
        </template>
        <div v-if="model.forget" class="submit" @click="type(0, 2)">{{ message('to-in') }}</div>
        <div v-else-if="model.submit" class="submit" @click="submit">{{ message('sign-' + model.type) }}</div>
      </div>
      <div v-if="model.inputs.length > 0 && model.inputs.length >= model.index" class="invalid">{{
        model.inputs[model.index - 1].invalid }}</div>
      <div v-if="model.invalid" class="invalid">{{ model.invalid }}</div>
    </div>
  </div>
</template>

<style scoped>
.stars,
.star {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
}

.stars {
  background-color: #040d21;
  background-image: url(./assets/hero-glow.svg);
  background-size: cover;
  background-position: center center;
}

.star {
  background-image: radial-gradient(2px 2px at 50px 200px, #eee, rgba(0, 0, 0, 0)), radial-gradient(2px 2px at 40px 70px, #fff, rgba(0, 0, 0, 0)), radial-gradient(3px 4px at 120px 40px, #ddd, rgba(0, 0, 0, 0));
  background-repeat: repeat;
  background-size: 250px 250px;
  opacity: 0;
  animation: zoom 10s infinite;
}

.star:nth-child(1) {
  background-position: 10% 90%;
  animation-delay: 0s
}

.star:nth-child(2) {
  background-position: 20% 50%;
  background-size: 270px 500px;
  animation-delay: .3s
}

.star:nth-child(3) {
  background-position: 40% -80%;
  animation-delay: 1.2s
}

.star:nth-child(4) {
  background-position: -20% -30%;
  transform: rotate(60deg);
  animation-delay: 2.5s
}

.star:nth-child(5) {
  background-image: radial-gradient(2px 2px at 10px 100px, #eee, rgba(0, 0, 0, 0)), radial-gradient(2px 2px at 20px 10px, #fff, rgba(0, 0, 0, 0)), radial-gradient(3px 4px at 150px 40px, #ddd, rgba(0, 0, 0, 0));
  background-position: 80% 30%;
  animation-delay: 4s
}

.star:nth-child(6) {
  background-position: 50% 20%;
  animation-delay: 6s
}

@keyframes zoom {
  0% {
    opacity: 0;
    transform: scale(0.5);
    transform: rotate(5deg);
    animation-timing-function: ease-in
  }

  85% {
    opacity: 1
  }

  100% {
    opacity: .2;
    transform: scale(2.2)
  }
}

@media(prefers-reduced-motion) {
  .star {
    animation: none
  }
}

.sign-in-up {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

@media screen and (max-width: 1080px) {
  .sign-in-up {
    left: 0;
    right: 0;
  }
}

@media screen and (min-width: 1080px) {
  .sign-in-up {
    left: 20vw;
    right: 20vw;
  }
}

.nav {
  width: calc(100% - 32px);
  padding: 16px;
  display: flex;
  justify-content: space-between;
}

.nav img {
  width: 32px;
  height: 32px;
}

.nav .langs{
  color:#8193b2;
  display: flex;
  column-gap: 8px;
  cursor: pointer;
}

.dialog {
  margin: 24px;
  padding: 24px;
  background-color: #0c162d;
  border: 1px solid #202637;
  border-radius: 6px;
}

.welcome {
  width: 33vw;
  min-width: 280px;
  color: #8193b2;
  text-align: center;
}

.label {
  margin-top: 24px;
  font-weight: 600;
  display: flex;
  align-items: center;
}

.label-0 {
  color: #00cfc8;
}

.label-01 {
  padding-left: 16px;
  color: #8193b2;
}

.label-02,
.label-11 {
  color: #FF8DC0;
  cursor: pointer;
}

.label-11 {
  padding-left: 16px;
}

.input {
  display: flex;
  align-items: center;
  padding-top: 4px;
}

.arrow {
  color: #ea4aaa;
}

.correct {
  color: #20bb3d;
  padding-right: 8px;
}

.input input {
  flex-grow: 1;
  outline: none;
  border: 1px solid #0c162d;
  background: none;
  color: #fff;
}

.input input:focus {
  border: 1px solid rgb(9, 105, 218);
}

.value {
  color: #fff;
}

.button-invalid,
.button-valid,
.button-empty {
  padding: 4px 8px;
  border-radius: 6px;
  white-space: nowrap;
}

.button-invalid {
  color: #627597;
  border: 1px solid #627597;
  cursor: default;
}

.button-valid,
.submit {
  color: #FF8DC0;
  border: 1px solid #FF8DC0;
  cursor: pointer;
}

.button-empty {
  color: #0c162d;
  border: 1px solid #0c162d;
  cursor: default;
}

.submit {
  text-align: center;
  padding: 8px 0;
  border-radius: 6px;
  margin-top: 24px;
}

.invalid {
  padding: 0 48px;
  color: #8193b2;
}
</style>
