import apiService from './apiService';
import API_CONFIG from '../config/api';

export interface PPMPlannerFilters {
  modality?: string; // 'Biomedical' | 'Non-Biomedical'
  asset_type?: string;
  department?: string;
  location?: string;
  manufacturer?: string;
  model?: string;
  company?: string;
}

export interface AssetEntry {
  name: string;
  custom_manufacturer?: string;
  custom_model?: string;
}

export interface BulkScheduleData {
  assets: AssetEntry[];
  start_date: string;
  end_date: string;
  maintenance_team?: string;
  assign_to?: string; // User to assign to
  maintenance_manager?: string; // Maintenance manager (auto-fetched from team)
  periodicity: string;
  maintenance_type?: string;
  no_of_pms?: string;
  pm_for?: string; // PM Name - required field
  hospital: string; // Required - Company/Hospital name
  modality?: string;
  manufacturer?: string;
  model?: string;
  department?: string;
}

export interface MaintenanceTeamDetails {
  name: string;
  maintenance_manager?: string;
  team_members?: string[]; // Array of user names
}

class PPMPlannerService {
  /**
   * Submit a PM Schedule Generator document
   */
  private async submitDocument(docName: string, headers: Record<string, string>): Promise<void> {
    try {
      // First, fetch the full document
      const getDocResponse = await this.fetchWithTimeout(
        `${API_CONFIG.BASE_URL}/api/resource/PM Schedule Generator/${encodeURIComponent(docName)}`,
        {
          method: 'GET',
          headers: {
            'Accept': 'application/json',
          },
          credentials: 'include',
        },
        30000
      );

      if (!getDocResponse.ok) {
        const errorText = await getDocResponse.text();
        console.warn('Failed to fetch document for submit:', errorText);
        return;
      }

      const docData = await getDocResponse.json();
      const fullDoc = docData.data;

      if (!fullDoc) {
        console.warn('No document data received');
        return;
      }

      // Now submit with the full document
      const submitResponse = await this.fetchWithTimeout(
        `${API_CONFIG.BASE_URL}/api/method/frappe.client.submit`,
        {
          method: 'POST',
          headers,
          credentials: 'include',
          body: JSON.stringify({
            doc: fullDoc
          })
        },
        60000 // 60 seconds for submit
      );

      if (!submitResponse.ok) {
        const errorText = await submitResponse.text();
        console.warn('Failed to submit document:', errorText);
        // Don't throw - document is created even if submit fails
      } else {
        console.log('✅ Document submitted successfully');
      }
    } catch (error: any) {
      console.warn('Error submitting document:', error.message);
      // Don't throw - document is created even if submit fails
    }
  }

  /**
   * Helper function to make fetch requests with timeout
   */
  private async fetchWithTimeout(
    url: string, 
    options: RequestInit, 
    timeoutMs: number = 120000 // 120 seconds for bulk operations
  ): Promise<Response> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
    
    try {
      const response = await fetch(url, {
        ...options,
        signal: controller.signal
      });
      clearTimeout(timeoutId);
      return response;
    } catch (error: any) {
      clearTimeout(timeoutId);
      if (error.name === 'AbortError') {
        throw new Error(`Request timeout after ${timeoutMs}ms. The server may be slow or the request is too large.`);
      }
      if (error.message?.includes('Failed to fetch') || error.message?.includes('ERR_CONNECTION_TIMED_OUT')) {
        throw new Error(`Connection timeout. Please check:\n1. Your internet connection\n2. Server is accessible\n3. Try with fewer assets`);
      }
      throw error;
    }
  }

  /**
   * Get filtered assets based on PPM planner criteria
   */
  async getFilteredAssets(filters: PPMPlannerFilters) {
    const filterArray: any[] = [];
    
    if (filters.modality) {
      filterArray.push(['custom_modality', '=', filters.modality]);
    }
    if (filters.asset_type) {
      filterArray.push(['custom_asset_type', '=', filters.asset_type]);
    }
    if (filters.department) {
      filterArray.push(['department', '=', filters.department]);
    }
    if (filters.location) {
      filterArray.push(['location', '=', filters.location]);
    }
    if (filters.manufacturer) {
      filterArray.push(['custom_manufacturer', '=', filters.manufacturer]);
    }
    if (filters.model) {
      filterArray.push(['custom_model', '=', filters.model]);
    }

    const filtersJson = JSON.stringify(filterArray);
    const fields = JSON.stringify([
      'name',
      'asset_name',
      'custom_asset_type',
      'department',
      'location',
      'custom_manufacturer',
      'custom_model',
      'custom_modality',
      'company'
    ]);

    const response = await apiService.apiCall<any>(
      `/api/resource/Asset?filters=${encodeURIComponent(filtersJson)}&fields=${encodeURIComponent(fields)}&limit_page_length=1000`
    );
    
    return response?.data || [];
  }

  /**
   * Create bulk maintenance schedules for multiple assets
   * Uses the existing "PM Schedule Generator" doctype workflow
   */
  async createBulkMaintenanceSchedules(data: BulkScheduleData) {
    // Validate required fields
    if (!data.hospital) {
      throw new Error('Hospital/Company is required to create PM Schedule Generator');
    }
    if (!data.periodicity) {
      throw new Error('Periodicity is required');
    }
    if (data.assets.length === 0) {
      throw new Error('At least one asset must be selected');
    }
    
    // Warn if too many assets (might cause timeout)
    if (data.assets.length > 50) {
      console.warn(`Creating schedules for ${data.assets.length} assets. This may take a while...`);
    }

    // Build the PM Schedule Generator document with correct structure
    const pmScheduleDoc = {
      doctype: 'PM Schedule Generator',
      hospital: data.hospital,        // Required: Link to Company
      start_date: data.start_date,    // Required: Date
      end_date: data.end_date,        // Required: Date
      periodicity: data.periodicity,  // Required: Select
      pm_for: data.pm_for || null,   // Required: PM Name
      no_of_pms: data.no_of_pms || null,
      maintenance_team: data.maintenance_team || null,
      maintenance_manager: data.maintenance_manager || null, // Auto-fetched from team
      assign_to: data.assign_to || null, // User to assign to (auto-selected if only one member)
      modality: data.modality || null,
      manufacturer: data.manufacturer || null,
      model: data.model || null,
      department: data.department || null,
      // Child table: PM Entry Line - each entry gets manufacturer and model from its own asset
      maintenance_entries: data.assets.map(asset => ({
        doctype: 'PM Entry Line',
        asset: asset.name,
        start_date: data.start_date,
        end_date: data.end_date,
        // Pick manufacturer and model from each asset, not from filter
        manufacturer: asset.custom_manufacturer || null,
        model: asset.custom_model || null,
      }))
    };

    console.log('Creating PM Schedule Generator with document:', JSON.stringify(pmScheduleDoc, null, 2));

    // Get CSRF token
    const csrfToken = await apiService.getCSRFToken();
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    };
    if (csrfToken) {
      headers['X-Frappe-CSRF-Token'] = csrfToken;
    }

    // Method 1: Try frappe.client.insert (best for child tables)
    try {
      const insertResponse = await this.fetchWithTimeout(
        `${API_CONFIG.BASE_URL}/api/method/frappe.client.insert`,
        {
          method: 'POST',
          headers,
          credentials: 'include',
          body: JSON.stringify({ doc: pmScheduleDoc })
        },
        120000 // 120 seconds timeout
      );

      const responseText = await insertResponse.text();
      console.log('frappe.client.insert response:', responseText);

      if (!insertResponse.ok) {
        throw new Error(`HTTP ${insertResponse.status}: ${responseText}`);
      }

      const insertResult = JSON.parse(responseText);
      const docName = insertResult?.message?.name;
      
      if (docName) {
        console.log('✅ PM Schedule Generator created successfully:', docName);
        
        // Submit the document
        await this.submitDocument(docName, headers);
        
        return {
          success: true,
          created: data.assets.length,
          document: docName,
          message: `PM Schedule Generator "${docName}" created and submitted with ${data.assets.length} assets`
        };
      }
      
      throw new Error('No document name in response');

    } catch (insertError: any) {
      console.warn('Method 1 (frappe.client.insert) failed:', insertError.message);
      
      // Method 2: Try Resource API
      try {
        // Remove doctype from document for Resource API
        const { doctype, maintenance_entries, ...parentDoc } = pmScheduleDoc;
        const resourceDoc = {
          ...parentDoc,
          maintenance_entries: maintenance_entries.map(({ doctype: _, ...entry }) => entry)
        };

        console.log('Trying Resource API with:', JSON.stringify(resourceDoc, null, 2));

        const resourceResponse = await this.fetchWithTimeout(
          `${API_CONFIG.BASE_URL}/api/resource/PM%20Schedule%20Generator`,
          {
            method: 'POST',
            headers,
            credentials: 'include',
            body: JSON.stringify(resourceDoc)
          },
          120000 // 120 seconds timeout
        );

        const responseText = await resourceResponse.text();
        console.log('Resource API response:', responseText);

        if (!resourceResponse.ok) {
          throw new Error(`HTTP ${resourceResponse.status}: ${responseText}`);
        }

        const resourceResult = JSON.parse(responseText);
        const docName = resourceResult?.data?.name;
        
        if (docName) {
          console.log('✅ PM Schedule Generator created via Resource API:', docName);
          
          // Submit the document
          await this.submitDocument(docName, headers);
          
          return {
            success: true,
            created: data.assets.length,
            document: docName,
            message: `PM Schedule Generator "${docName}" created and submitted with ${data.assets.length} assets`
          };
        }
        
        throw new Error('No document name in response');
        
      } catch (resourceError: any) {
        console.warn('Method 2 (Resource API) failed:', resourceError.message);
        
        // Both methods failed - provide helpful error message
        const errorSummary: string[] = [];
        
        // Check if all errors are timeouts
        const allTimeouts = 
          (insertError?.message?.includes('timeout') || insertError?.message?.includes('Failed to fetch')) &&
          (resourceError?.message?.includes('timeout') || resourceError?.message?.includes('Failed to fetch'));
        
        if (allTimeouts) {
          errorSummary.push(
            `⚠️ Connection timeout detected. This usually means:\n` +
            `• The server is taking too long to process ${data.assets.length} assets\n` +
            `• Network connection is slow or unstable\n` +
            `• Server may be overloaded\n\n` +
            `💡 Suggestions:\n` +
            `• Try with fewer assets (10-20 at a time)\n` +
            `• Check your internet connection\n` +
            `• Try again later if server is busy`
          );
        } else {
          errorSummary.push(`Failed to create PM Schedule Generator. Errors:`);
          if (insertError?.message) {
            errorSummary.push(`• frappe.client.insert: ${insertError.message.substring(0, 150)}`);
          }
          if (resourceError?.message) {
            errorSummary.push(`• Resource API: ${resourceError.message.substring(0, 150)}`);
          }
          errorSummary.push(`\nPlease ensure:\n1. Hospital (${data.hospital}) is valid\n2. You have permission to create PM Schedule Generator\n3. All required fields are filled (including PM Name and Assign To)`);
        }
        
        throw new Error(`Failed to create PM Schedule Generator.\n\n${errorSummary.join('\n')}`);
      }
    }
  }

  /**
   * Get filter options for dropdowns
   */
  async getFilterOptions() {
    try {
      const response = await apiService.apiCall<any>(
        `/api/resource/Asset?fields=${encodeURIComponent(JSON.stringify(['custom_modality', 'custom_asset_type', 'department', 'location', 'custom_manufacturer', 'custom_model']))}&limit_page_length=1000`
      );
      
      const assets = response?.data || [];
      const options = {
        modalities: [...new Set(assets.map((a: any) => a.custom_modality).filter(Boolean))] as string[],
        assetTypes: [...new Set(assets.map((a: any) => a.custom_asset_type).filter(Boolean))] as string[],
        departments: [...new Set(assets.map((a: any) => a.department).filter(Boolean))] as string[],
        locations: [...new Set(assets.map((a: any) => a.location).filter(Boolean))] as string[],
        manufacturers: [...new Set(assets.map((a: any) => a.custom_manufacturer).filter(Boolean))] as string[],
        models: [...new Set(assets.map((a: any) => a.custom_model).filter(Boolean))] as string[],
        company: [...new Set(assets.map((a: any) => a.company).filter(Boolean))] as string[]
      };
      
      return options;
    } catch (error) {
      console.error('Error fetching filter options:', error);
      return {
        modalities: [],
        assetTypes: [],
        departments: [],
        locations: [],
        manufacturers: [],
        models: [],
        company:  [],
      };
    }
  }

  /**
   * Get maintenance teams
   */
  async getMaintenanceTeams() {
    try {
      const response = await apiService.apiCall<any>(
        `/api/resource/Asset Maintenance Team?fields=${encodeURIComponent(JSON.stringify(['name']))}&limit_page_length=1000`
      );
      
      if (response?.data && response.data.length > 0) {
        return response.data.map((team: any) => ({
          name: team.name,
          maintenance_team_name: team.name
        }));
      }
      return [];
    } catch (error: any) {
      console.warn('Could not fetch maintenance teams:', error?.message || 'Unknown error');
      return [];
    }
  }

  /**
   * Get maintenance team details including manager and members
   */
  async getMaintenanceTeamDetails(teamName: string): Promise<MaintenanceTeamDetails | null> {
    try {
      const response = await apiService.apiCall<any>(
        `/api/resource/Asset Maintenance Team/${encodeURIComponent(teamName)}`
      );
      
      if (response?.data) {
        const team = response.data;
        const teamMembers: string[] = [];
        if (team.maintenance_team_members && Array.isArray(team.maintenance_team_members)) {
          team.maintenance_team_members.forEach((member: any) => {
            if (member.team_member) {
              teamMembers.push(member.team_member);
            }
          });
        }
        
        return {
          name: team.name,
          maintenance_manager: team.maintenance_manager || undefined,
          team_members: teamMembers.length > 0 ? teamMembers : undefined
        };
      }
      return null;
    } catch (error: any) {
      console.warn('Could not fetch maintenance team details:', error?.message || 'Unknown error');
      return null;
    }
  }
}

export default new PPMPlannerService();