<template>
  <div class="login-page page" :class="{ 'loading-blur': isLoading }" :style="{ 'cursor': isLoading ? 'wait' : '' }">
    <div>
      <div class="background-img">
        <p>
          어서오세요.<br />
          로그인하세요.
        </p>
      </div>

      <!-- 일반 로그인 화면 -->
      <div class="login-wrap" v-if="!loginStep1 && !loginStep2">
        <div class="login">
          <div :class="{ 'login-title': true, 'user-login': !isAdminPage }">
            <router-link :to="{ path: $filters.ctxPath('/') }">LOGIN(홈으로 이동)</router-link>
          </div>

          <!-- 아이디/비밀번호 입력 -->
          <div class="form-group">
            <label for="id" class="login-label">아이디</label>
            <input type="text" id="id" class="form-control md" placeholder="아이디를 입력하세요" v-model="member.lgnId" />
          </div>
          <div class="form-group">
            <label for="pw" class="login-label">비밀번호</label>
            <input type="password" id="pw" class="form-control md" placeholder="비밀번호를 입력하세요" 
                   v-model="member.pswd" @keydown.enter="fnLogin" />
          </div>

          <!-- 로그인 버튼 -->
          <button class="btn md main" :class="{ 'user-btn': !isAdminPage }" @click="fnLogin" @keydown.enter="fnLogin">
            로그인
          </button>

          <!-- 사용자 페이지 전용 기능 -->
          <div v-if="!isAdminPage">
            <!-- 아이디/비밀번호 찾기 -->
            <div class="input-group">
              <p class="pl10 pr10 cursor" @click="moveSignUp">회원가입</p>
              <p class="pl10 pr10 cursor" @click="moveSearchId">아이디 찾기</p>
              <p class="pl10 pr0 cursor" @click="moveResetPswd">비밀번호 찾기</p>
            </div>

            <!-- OAuth2 소셜 로그인 -->
            <div>
              <div><span>또는</span></div>
              <div>
                <button @click="fnOAuthLogin('kakao')" :disabled="isOAuthLoading">카카오로 로그인</button>
                <button @click="fnOAuthLogin('naver')" :disabled="isOAuthLoading">네이버로 로그인</button>
                <button @click="fnOAuthLogin('google')" :disabled="isOAuthLoading">구글로 로그인</button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 2차 인증 화면 -->
      <div class="login-wrap" v-else-if="loginStep1 && !loginStep2">
        <div>
          <p>인증코드 입력</p>
          <p>{{memberInfo.email}}로 전송된 6자리 인증코드를 입력하세요.</p>
          <input type="text" class="form-control md" ref="code" @input="inputCode" 
                 v-model="memberInfo.code" maxlength="6" placeholder="인증코드를 입력하세요." />
        </div>
        <div class="btn-wrap">
          <button class="btn sm main" @click="fnCheck">인증코드 확인</button>
        </div>
        <div>
          <p>인증코드를 받지 못하셨나요?</p>
          <button class="btn sm tertiary" @click="fnResend">인증코드 다시받기</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { useStore } from "vuex";
import { loginProc, getUserInfo, oauthLogin } from "../../../resources/api/login";
import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email";
import queryParams from "../../../resources/js/queryParams";

export default {
  mixins: [queryParams],

  data() {
    return {
      isLoading: false,
      member: { lgnId: null, pswd: null, lgnReqPage: 'U' },
      isAdminPage: false,
      isOAuthLoading: false,
      memberInfo: { email: '', code: '' },
      loginStep1: false, // 1차 인증
      loginStep2: false, // 2차 인증
    };
  },

  async created() {
    this.checkAdminPage();
  },

  async mounted() {
      await this.$nextTick();
      if (this.hasOAuthParams()) {
        await this.handleOAuthCallback();
      }
    },
  beforeUnmount() {
    this.isOAuthLoading = false;
  },

  watch: {
    '$route'(to) {
      if (to.query.oauth_success || to.query.error) {
        this.handleOAuthCallback();
      }
    }
  },

  methods: {
    // ========== 초기화 ==========
    checkAdminPage() {
      const redirect = this.restoreRedirect("redirect");
      this.isAdminPage = redirect && redirect.includes("/adm/");
    },

    hasOAuthParams() {
      return window.location.search.includes('oauth_success') ||
        window.location.search.includes('error') ||
        this.$route.query.oauth_success ||
        this.$route.query.error;
    },

    // ========== 일반 로그인 ==========
    async fnLogin() {
      this.isLoading = true;
      try {
        const res = await loginProc(this.member);
        if (res.status !== 200) return;

        if (res.data.email) {
          this.memberInfo = res.data;
        } else {
          this.loginStep2 = true;
          await this.loginSuccessProc(res);
        }
        this.loginStep1 = true;

      } catch (error) {
        alert(error.response?.data?.message || "로그인에 실패했습니다.");
      } finally {
        this.isLoading = false;
      }
    },

    async loginSuccessProc(res) {
      const loginMode = res.headers['loginmode'];     // J, S
      const policyMode = res.headers['policymode'];   // Y, N
      
      this.$store.commit("setLoginMode", loginMode || 'J');
      this.$store.commit("setPolicyMode", policyMode || 'Y');
      
      if (loginMode === 'J') {
        this.handleJWTLogin(res);
      } else if (loginMode === 'S') {
        this.handleSessionLogin(res);
      } else {
        alert("알 수 없는 로그인 방식입니다.");
        return;
      }
      await this.handleLoginSuccess();
    },

    handleJWTLogin(res) {
      const token = res.headers.authorization;
      const userInfo = this.parseJWT(token);
      this.setAuthInfo("J", token, userInfo);
    },

    handleSessionLogin(res) {
      const userInfo = res.data;
      const roles = userInfo.roles.map(r => ({ authority: r.authrtCd }));
      this.setAuthInfo("S", null, { ...userInfo, roles });
    },

    parseJWT(token) {
      const base64String = token.split(".")[1];
      const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/");
      const jsonPayload = decodeURIComponent(
        atob(base64).split("").map((c) => {
          return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
        }).join("")
      );
      return JSON.parse(jsonPayload);
    },

    // ========== 2차 인증 ==========
    inputCode(event) {
      const input = event.target.value.replace(/[^0-9]/g, '');
      this.memberInfo.code = input;
    },

    async fnCheck() {
      try {
        const res = await check2ndAuthProc(this.memberInfo);
        if (res.status == 200) {
          await this.loginSuccessProc(res);
        }
      } catch (error) {
        const errorData = error.response.data;
        if (errorData.message != null && errorData.message != "") {
          alert(error.response.data.message);
          this.$refs.code.focus();
        } else {
          alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
        }
      }
    },

    async fnResend() {
      this.isLoading = true;
      try {
        const res = await sendAuthEmailProc(this.memberInfo);
        if (res.status == 200) {
          alert(res.data.message);
        }
      } catch (error) {
        const errorData = error.response.data;
        if (errorData.message != null && errorData.message != "") {
          alert(error.response.data.message);
        } else {
          alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
        }
      } finally {
        this.isLoading = false;
      }
    },

    // ========== OAuth2 로그인 ==========
    fnOAuthLogin(provider) {
      this.isOAuthLoading = true;
      
      const redirectUrl = this.restoreRedirect("redirect") || this.$route.fullPath;
      sessionStorage.setItem('oauth_redirect', redirectUrl);
      sessionStorage.setItem('oauth_provider', provider);
      sessionStorage.setItem('oauth_start_time', Date.now().toString());
      
      oauthLogin(provider);
    },

    async handleOAuthCallback() {
      const { error, errorMessage, oauthSuccess, loginMode, policyMode } = this.parseOAuthParams();
      if (error) {
        this.handleOAuthError(error, errorMessage);
        return;
      }

      if (oauthSuccess !== 'true' && oauthSuccess !== true) {
        return;
      }

      try {
        const finalLoginMode = loginMode || this.$store.state.loginMode || 'J';
        const finalPolicyMode = policyMode || this.$store.state.policyMode || 'Y';
        
        this.$store.commit("setLoginMode", finalLoginMode);
        this.$store.commit("setPolicyMode", finalPolicyMode);

        if (finalLoginMode === 'J') {
          await this.handleOAuthJWT();
        } else {
          await this.handleOAuthSession();
        }

        this.cleanupOAuth();
        await this.$nextTick();
        await this.handleLoginSuccess();

      } catch (error) {
        this.handleOAuthError('processing_error', error.message);
      }
    },

    parseOAuthParams() {
      const urlParams = new URLSearchParams(window.location.search);
      const routeQuery = this.$route.query;

      return {
        error: urlParams.get('error') || routeQuery.error,
        errorMessage: urlParams.get('message') || routeQuery.message,
        oauthSuccess: urlParams.get('oauth_success') || routeQuery.oauth_success,
        loginMode: urlParams.get('loginMode') || routeQuery.loginMode,      // J, S
        policyMode: urlParams.get('policyMode') || routeQuery.policyMode    // Y, N
      };
    },

    async handleOAuthJWT() {
      try {
        
        // 여러 방법으로 토큰 찾기
        const token = this.getCookie('Authorization') 
            || this.getCookie('refresh') 
            || localStorage.getItem('authorization')
            || sessionStorage.getItem('authorization');
            
        const headers = { 
          'Content-Type': 'application/json',
          'Cache-Control': 'no-cache'
        };
        
        if (token) {
          headers['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`;
        }
        const response = await fetch('/oauth2/getUserInfo.json', {
          method: 'POST',
          headers: headers,
          credentials: 'include'
        });



        if (response.status === 200) {
          const result = await response.json();
          
          if (result.success || result.data) {
            const userInfo = result.data;
            
            // 토큰이 응답에 있으면 사용, 없으면 기존 토큰 사용
            const finalToken = result.data.token || token;
            
            const roles = Array.isArray(userInfo.roles) ?
                userInfo.roles.map(r => ({ authority: r.authrtCd || r.authority })) :
                userInfo.roles;

            this.setAuthInfo("J", finalToken, { ...userInfo, roles });
            
          } else {
            throw new Error('서버에서 실패 응답');
          }
        } else {
          throw new Error('API 호출 실패: ' + response.status);
        }
        
      } catch (error) {
        throw error;
      }
    },

    async handleOAuthSession() {
      try {

          const userInfoRes = await fetch('/oauth2/getUserInfo.json', {
          method: 'POST',
          credentials: 'include',
          headers: {
            'Content-Type': 'application/json',
            'Cache-Control': 'no-cache'
          }
        });
        
        if (!userInfoRes || userInfoRes.status !== 200) {
          throw new Error('세션 정보를 가져올 수 없습니다.');
        }

        const result = await userInfoRes.json();
        
        const userInfo = result.data;
        const roles = Array.isArray(userInfo.roles) ?
          userInfo.roles.map(r => ({ authority: r.authrtCd || r.authority })) :
          userInfo.roles;

        this.setAuthInfo('S', null, { ...userInfo, roles });
        
      } catch (error) {
        throw error;
      }
    },

    // ========== 공통 처리 ==========
    setAuthInfo(loginMode, token, userInfo) {
      
      // Store 설정
      try {
        if (typeof this.$store !== 'undefined' && this.$store.commit) {
          this.$store.commit("setLoginMode", loginMode);
          this.$store.commit("setAuthorization", token);
          this.$store.commit("setMbrId", userInfo.mbrId);
          this.$store.commit("setMbrNm", userInfo.mbrNm);
          this.$store.commit("setRoles", userInfo.roles);
        }
      } catch (e) {
        console.warn("store 설정 실패:", e);
      }
    },

    async handleLoginSuccess() {
      
      const isAdmin = this.$store.state.roles.some(role => role.authority === "ROLE_ADMIN");
      let redirectUrl = this.restoreRedirect("redirect") || sessionStorage.getItem('oauth_redirect');

      if (redirectUrl && this.shouldRedirectToMain(redirectUrl)) {
        redirectUrl = this.$filters.ctxPath("/");
      }

      if (redirectUrl && !redirectUrl.startsWith(this.$store.state.contextPath) && this.$store.state.contextPath) {
        redirectUrl = this.$filters.ctxPath(redirectUrl);
      }

      const targetPath = this.getValidRedirectPath(redirectUrl, isAdmin);
      
      await this.$nextTick();
      this.$router.push({ path: targetPath });

      sessionStorage.removeItem("redirect");
      sessionStorage.removeItem("oauth_redirect");
    },

    shouldRedirectToMain(url) {
      return url.includes("/searchId.page") ||
        url.includes("/resetPswd.page") ||
        url.includes("/login.page") ||
        url.includes("/cmslogin.page");
    },

    getValidRedirectPath(redirectUrl, isAdmin) {
      if (redirectUrl && !redirectUrl.includes("login.page") && !redirectUrl.includes("cmslogin.page")) {
        const routeExists = this.$router.getRoutes().some(route => route.path === redirectUrl);
        if (routeExists) return redirectUrl;
      }

      return isAdmin ?
        this.$filters.ctxPath("/adm/main.page") :
        this.$filters.ctxPath("/");
    },

    // ========== 에러 처리 및 정리 ==========
    handleOAuthError(error, errorMessage) {
      
      this.isOAuthLoading = false;
      this.cleanupOAuth();

      const message = decodeURIComponent(errorMessage || error || 'OAuth 로그인에 실패했습니다.');

      // 현재 페이지가 메인 페이지가 아니면 로그인 페이지로 이동
      if (this.$route.path !== this.$filters.ctxPath("/")) {
        this.$router.push({ path: this.$filters.ctxPath("/login.page") });
      }
    },

    cleanupOAuth() {
      
      sessionStorage.removeItem('oauth_redirect');
      sessionStorage.removeItem('oauth_provider');
      sessionStorage.removeItem('oauth_start_time');
      this.isOAuthLoading = false;

      // URL에서 OAuth 파라미터 제거
      const cleanUrl = window.location.pathname;
      window.history.replaceState({}, document.title, cleanUrl);
    },

    // ========== 유틸리티 ==========
    getCookie(name) {
      const value = `; ${document.cookie}`;
      const parts = value.split(`; ${name}=`);
      if (parts.length === 2) {
        const cookieValue = parts.pop().split(';').shift();
        return cookieValue;
      }
      return null;
    },

    moveSignUp() {
      this.$router.push({
        path: this.$filters.ctxPath("/signUp.page"),
      });
    },

    moveSearchId() {
      this.$router.push({
        path: this.$filters.ctxPath("/resetPswd.page"),
        query: { tab: "id" }
      });
    },

    moveResetPswd() {
      this.$router.push({
        path: this.$filters.ctxPath("/resetPswd.page"),
        query: { tab: "pw" }
      });
    }
  }
};
</script>

<style scoped>
.loading-blur {
  pointer-events: none;
  opacity: 0.4;
  filter: grayscale(20%) blur(1px);
}
</style>