/**
 * Trackex API Client
 * 
 * Handles all interactions with the Trackex backend API
 * including authentication token exchange and task operations
 */

import { Env } from './index';
import { TrackexTask, TrackexTaskCreateRequest, TrackexAPIResponse, TrackexUser } from './types';

export interface TrackexSession {
	userId: string;
	token: string;
	expiresIn: number;
}

export class TrackexAPIClient {
	private env: Env;
	private baseUrl: string;
	private isMockMode: boolean;

	constructor(env: Env) {
		this.env = env;
		this.baseUrl = env.TRACKEX_API_BASE_URL || 'https://api.trackex.co';
		// Enable mock mode if TRACKEX_MOCK_MODE is set to 'true' or if API base URL contains 'mock'
		this.isMockMode = env.TRACKEX_MOCK_MODE === 'true' || this.baseUrl.includes('mock');
	}

	/**
	 * Create a Trackex session using Microsoft access token
	 * Supports both real API and mock mode for development/testing
	 */
	async createSession(microsoftToken: string, userInfo: any): Promise<TrackexSession> {
		if (this.isMockMode) {
			return this.createMockSession(microsoftToken, userInfo);
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/auth/microsoft-token`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
					'Authorization': `Bearer ${microsoftToken}`,
				},
				body: JSON.stringify({
					userInfo: {
						email: userInfo.mail || userInfo.userPrincipalName,
						name: userInfo.displayName,
						tenantId: userInfo.tid || 'common'
					}
				}),
			});

			if (!response.ok) {
				// If API endpoint doesn't exist yet, fall back to mock mode
				if (response.status === 404) {
					console.warn('Trackex API endpoint not found, falling back to mock mode');
					return this.createMockSession(microsoftToken, userInfo);
				}
				throw new Error(`Failed to create Trackex session: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<{ token: string; user: TrackexUser; expiresIn: number }> = await response.json();
			
			if (!data.success || !data.data) {
				throw new Error(data.error || 'Failed to create session');
			}

			return {
				userId: data.data.user.id.toString(),
				token: data.data.token,
				expiresIn: data.data.expiresIn || 3600
			};

		} catch (error) {
			console.error('Failed to create Trackex session:', error);
			
			// If there's a network error or API is down, fall back to mock mode
			if (error instanceof TypeError && error.message.includes('fetch')) {
				console.warn('Trackex API unreachable, falling back to mock mode');
				return this.createMockSession(microsoftToken, userInfo);
			}
			
			throw error;
		}
	}

	/**
	 * Create a mock Trackex session for development/testing
	 */
	private async createMockSession(microsoftToken: string, userInfo: any): Promise<TrackexSession> {
		console.log('🎭 Creating mock Trackex session for user:', userInfo.displayName);
		
		// Generate a mock session token (base64 encoded user info + timestamp)
		const mockTokenData = {
			userId: userInfo.id,
			email: userInfo.mail || userInfo.userPrincipalName,
			name: userInfo.displayName,
			timestamp: Date.now(),
			provider: 'microsoft-mock'
		};
		
		const mockToken = btoa(JSON.stringify(mockTokenData));
		
		return {
			userId: userInfo.id,
			token: `mock_${mockToken}`,
			expiresIn: 3600 // 1 hour
		};
	}

	/**
	 * Get today's tasks for the authenticated user
	 */
	async getTodayTasks(trackexToken: string): Promise<TrackexTask[]> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.getMockTasks('today');
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/tasks/today`, {
				method: 'GET',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
			});

			if (!response.ok) {
				throw new Error(`Failed to get today's tasks: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<TrackexTask[]> = await response.json();
			
			if (!data.success) {
				throw new Error(data.error || 'Failed to fetch tasks');
			}

			return data.data || [];

		} catch (error) {
			console.error('Failed to get today tasks:', error);
			// Fall back to mock data if API fails
			console.warn('Falling back to mock tasks data');
			return this.getMockTasks('today');
		}
	}

	/**
	 * Get today's ad-hoc tasks for the authenticated user
	 */
	async getTodayAdhocTasks(trackexToken: string): Promise<TrackexTask[]> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.getMockTasks('adhoc');
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/tasks/today/adhoc`, {
				method: 'GET',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
			});

			if (!response.ok) {
				throw new Error(`Failed to get today's ad-hoc tasks: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<TrackexTask[]> = await response.json();
			
			if (!data.success) {
				throw new Error(data.error || 'Failed to fetch ad-hoc tasks');
			}

			return data.data || [];

		} catch (error) {
			console.error('Failed to get today ad-hoc tasks:', error);
			// Fall back to mock data if API fails
			console.warn('Falling back to mock adhoc tasks data');
			return this.getMockTasks('adhoc');
		}
	}

	/**
	 * Get today's pending tasks for the authenticated user
	 */
	async getTodayPendingTasks(trackexToken: string): Promise<TrackexTask[]> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.getMockTasks('pending');
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/tasks/today/pending`, {
				method: 'GET',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
			});

			if (!response.ok) {
				throw new Error(`Failed to get today's pending tasks: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<TrackexTask[]> = await response.json();
			
			if (!data.success) {
				throw new Error(data.error || 'Failed to fetch pending tasks');
			}

			return data.data || [];

		} catch (error) {
			console.error('Failed to get today pending tasks:', error);
			// Fall back to mock data if API fails
			console.warn('Falling back to mock pending tasks data');
			return this.getMockTasks('pending');
		}
	}

	/**
	 * Create a new task
	 */
	async createTask(trackexToken: string, taskData: TrackexTaskCreateRequest): Promise<TrackexTask> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.createMockTask(taskData);
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/tasks`, {
				method: 'POST',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
				body: JSON.stringify(taskData),
			});

			if (!response.ok) {
				throw new Error(`Failed to create task: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<TrackexTask> = await response.json();
			
			if (!data.success || !data.data) {
				throw new Error(data.error || 'Failed to create task');
			}

			return data.data;

		} catch (error) {
			console.error('Failed to create task:', error);
			// Fall back to mock creation if API fails
			console.warn('Falling back to mock task creation');
			return this.createMockTask(taskData);
		}
	}

	/**
	 * Validate a Trackex session token
	 */
	async validateSession(trackexToken: string): Promise<boolean> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.validateMockSession(trackexToken);
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/auth/validate`, {
				method: 'GET',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
			});

			return response.ok;

		} catch (error) {
			console.error('Failed to validate session:', error);
			// Fall back to mock validation if API fails
			return this.validateMockSession(trackexToken);
		}
	}

	/**
	 * Get user information from Trackex API
	 */
	async getUserInfo(trackexToken: string): Promise<TrackexUser | null> {
		if (this.isMockMode || trackexToken.startsWith('mock_')) {
			return this.getMockUserInfo(trackexToken);
		}

		try {
			const response = await fetch(`${this.baseUrl}/api/user/me`, {
				method: 'GET',
				headers: {
					'Authorization': `Bearer ${trackexToken}`,
					'Content-Type': 'application/json',
				},
			});

			if (!response.ok) {
				throw new Error(`Failed to get user info: ${response.statusText}`);
			}

			const data: TrackexAPIResponse<TrackexUser> = await response.json();
			
			if (!data.success || !data.data) {
				throw new Error(data.error || 'Failed to get user info');
			}

			return data.data;

		} catch (error) {
			console.error('Failed to get user info:', error);
			// Fall back to mock user info if API fails
			return this.getMockUserInfo(trackexToken);
		}
	}

	// Mock data methods
	private getMockTasks(type: 'today' | 'adhoc' | 'pending'): TrackexTask[] {
		const baseTasks: TrackexTask[] = [
			{
				id: 1,
				title: `Review ${type} project requirements`,
				description: `Mock task for ${type} tasks - review and analyze project requirements`,
				priority: 'high',
				status: 'in_progress',
				due_date: new Date().toISOString().split('T')[0],
				created_at: new Date(Date.now() - 86400000).toISOString(),
				updated_at: new Date().toISOString(),
				created_by: 1,
				is_adhoc: type === 'adhoc',
				is_pending: type === 'pending'
			},
			{
				id: 2,
				title: `Complete ${type} documentation`,
				description: `Mock task for ${type} tasks - write comprehensive documentation`,
				priority: 'medium',
				status: type === 'pending' ? 'pending' : 'todo',
				due_date: new Date(Date.now() + 86400000).toISOString().split('T')[0],
				created_at: new Date(Date.now() - 43200000).toISOString(),
				updated_at: new Date().toISOString(),
				created_by: 1,
				is_adhoc: type === 'adhoc',
				is_pending: type === 'pending'
			}
		];

		return baseTasks.map(task => ({
			...task,
			title: task.title.replace(type, type.charAt(0).toUpperCase() + type.slice(1))
		}));
	}

	private createMockTask(taskData: TrackexTaskCreateRequest): TrackexTask {
		const now = new Date().toISOString();
		return {
			id: Math.floor(Math.random() * 10000) + 1000,
			title: taskData.title,
			description: taskData.description,
			priority: taskData.priority || 'medium',
			status: 'todo',
			due_date: taskData.due_date,
			created_at: now,
			updated_at: now,
			created_by: 1,
			is_adhoc: false,
			is_pending: false
		};
	}

	private validateMockSession(trackexToken: string): boolean {
		if (!trackexToken.startsWith('mock_')) {
			return false;
		}

		try {
			// Extract and validate the mock token
			const tokenData = trackexToken.substring(5); // Remove 'mock_' prefix
			const decoded = JSON.parse(atob(tokenData));
			
			// Check if token is not expired (mock tokens expire after 1 hour)
			const tokenAge = Date.now() - decoded.timestamp;
			return tokenAge < 3600000; // 1 hour in milliseconds
		} catch (error) {
			console.error('Invalid mock token:', error);
			return false;
		}
	}

	private getMockUserInfo(trackexToken: string): TrackexUser | null {
		if (!trackexToken.startsWith('mock_')) {
			return null;
		}

		try {
			const tokenData = trackexToken.substring(5);
			const decoded = JSON.parse(atob(tokenData));
			
			return {
				id: 1,
				email: decoded.email,
				name: decoded.name,
				role: 'user'
			};
		} catch (error) {
			console.error('Failed to get mock user info:', error);
			return null;
		}
	}
} 