import { defineStore } from 'pinia'
import type { UserInfo, TokenResponse, LoginRecord, ClientInfo } from '@/types'

export const useAuthStore = defineStore('auth', {
  state: (): {
    user: UserInfo | null;
    token: TokenResponse | null;
    loginHistory: LoginRecord[];
    clientInfo: ClientInfo | null;
    isRefreshing: boolean;
    refreshTimeout: number | null;
  } => ({
    user: null,
    token: null,
    loginHistory: [],
    clientInfo: null,
    isRefreshing: false,
    refreshTimeout: null
  }),

  getters: {
    isAuthenticated: (state) => !!state.token?.access_token,
    getUsername: (state) => state.user?.username || '',
    getNickname: (state) => state.user?.nickname || '',
    getAvatar: (state) => state.user?.avatar || '',
    getAccessToken: (state) => state.token?.access_token || '',
    getRefreshToken: (state) => state.token?.refresh_token || '',
    isTokenExpired: (state) => {
      if (!state.token?.expires_in) return true;
      const expireTime = localStorage.getItem('token_expire_time');
      if (!expireTime) return true;
      return Date.now() > parseInt(expireTime);
    }
  },

  actions: {
    // Set user information
    setUser(user: UserInfo) {
      this.user = user;
      localStorage.setItem('user_info', JSON.stringify(user));
    },

    // Set token information
    setToken(token: TokenResponse) {
      this.token = token;
      // Calculate and store expire time
      const expireTime = Date.now() + (token.expires_in * 1000);
      localStorage.setItem('auth_token', JSON.stringify(token));
      localStorage.setItem('token_expire_time', expireTime.toString());
      localStorage.setItem('refresh_token', token.refresh_token);
      
      // Set up automatic refresh before token expires
      this.setupTokenRefresh();
    },

    // Set client information
    setClientInfo(clientInfo: ClientInfo) {
      this.clientInfo = clientInfo;
    },

    // Add login record
    addLoginRecord(record: LoginRecord) {
      this.loginHistory.unshift(record);
      // Keep only the last 10 records
      if (this.loginHistory.length > 10) {
        this.loginHistory.pop();
      }
    },

    // Clear all auth information (logout)
    logout() {
      this.user = null;
      this.token = null;
      this.clientInfo = null;
      // Clear from localStorage
      localStorage.removeItem('auth_token');
      localStorage.removeItem('user_info');
      localStorage.removeItem('token_expire_time');
      localStorage.removeItem('refresh_token');
      // Clear refresh timeout
      this.clearTokenRefresh();
    },

    // Load auth information from localStorage
    loadFromStorage() {
      const token = localStorage.getItem('auth_token');
      const user = localStorage.getItem('user_info');
      
      if (token) {
        this.token = JSON.parse(token);
        // Set up automatic refresh if token is valid
        this.setupTokenRefresh();
      }
      
      if (user) {
        this.user = JSON.parse(user);
      }
    },

    // Refresh token
    async refreshToken() {
      if (this.isRefreshing || !this.getRefreshToken) return;
      
      try {
        this.isRefreshing = true;
        
        const response = await fetch('http://localhost:8080/oauth2/token', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': `Basic ${btoa('system-client:secret')}`
          },
          body: new URLSearchParams({
            grant_type: 'refresh_token',
            refresh_token: this.getRefreshToken
          })
        });
        
        if (!response.ok) {
          throw new Error('Failed to refresh token');
        }
        
        const newToken = await response.json();
        this.setToken(newToken);
        
        return newToken;
      } catch (error) {
        console.error('Token refresh failed:', error);
        this.logout();
        throw error;
      } finally {
        this.isRefreshing = false;
      }
    },

    // Setup automatic token refresh
    setupTokenRefresh() {
      // Clear existing timeout
      this.clearTokenRefresh();
      
      if (!this.token?.expires_in) return;
      
      const expireTime = localStorage.getItem('token_expire_time');
      if (!expireTime) return;
      
      // Refresh token 30 seconds before expiration
      const refreshTime = parseInt(expireTime) - 30000;
      const delay = refreshTime - Date.now();
      
      if (delay > 0) {
        this.refreshTimeout = window.setTimeout(() => {
          this.refreshToken();
        }, delay);
      }
    },

    // Clear token refresh timeout
    clearTokenRefresh() {
      if (this.refreshTimeout) {
        clearTimeout(this.refreshTimeout);
        this.refreshTimeout = null;
      }
    },

    // Get user info from UserInfo endpoint
    async fetchUserInfo() {
      try {
        const response = await fetch('http://localhost:8080/userinfo', {
          headers: {
            'Authorization': `Bearer ${this.getAccessToken}`
          }
        });
        
        if (!response.ok) {
          throw new Error('Failed to fetch user info');
        }
        
        const userInfo = await response.json();
        this.setUser(userInfo);
        return userInfo;
      } catch (error) {
        console.error('Failed to fetch user info:', error);
        // Try to refresh token and retry
        try {
          await this.refreshToken();
          const response = await fetch('http://localhost:8080/userinfo', {
            headers: {
              'Authorization': `Bearer ${this.getAccessToken}`
            }
          });
          
          if (response.ok) {
            const userInfo = await response.json();
            this.setUser(userInfo);
            return userInfo;
          }
        } catch (refreshError) {
          console.error('Retry failed after token refresh:', refreshError);
        }
        throw error;
      }
    },

    // Login with username and password
    async loginWithPassword(username: string, password: string) {
      try {
        const response = await fetch('http://localhost:8080/oauth2/token', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': `Basic ${btoa('system-client:secret')}`
          },
          body: new URLSearchParams({
            grant_type: 'password',
            username,
            password,
            scope: 'openid profile read write'
          })
        });
        
        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.error_description || 'Login failed');
        }
        
        const tokenData = await response.json();
        this.setToken(tokenData);
        await this.fetchUserInfo();
        
        return tokenData;
      } catch (error) {
        console.error('Password login failed:', error);
        throw error;
      }
    },

    // Login with SMS code
    async loginWithSms(phone: string, code: string) {
      try {
        const response = await fetch('http://localhost:8080/api/sms/login', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ phone, code })
        });
        
        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.message || 'SMS login failed');
        }
        
        const data = await response.json();
        this.setToken(data.data);
        await this.fetchUserInfo();
        
        return data.data;
      } catch (error) {
        console.error('SMS login failed:', error);
        throw error;
      }
    }
  }
})