import { Injectable, inject } from '@angular/core';
import { Observable, throwError, map, catchError } from 'rxjs';
import { ApiService, validateId, validatePagination } from '../../../core/services/api.service';
import {
  WorkflowResponseDto,
  CreateWorkflowDto,
  UpdateWorkflowDto,
  PaginatedWorkflowsResponse,
  WorkflowValidationResultDto,
} from '../../../api/models';

/**
 * Ensures response has valid data array for paginated workflows
 */
function ensureValidPaginatedResponse(
  response: PaginatedWorkflowsResponse | null | undefined,
  page: number,
  limit: number
): PaginatedWorkflowsResponse {
  if (!response) {
    return {
      data: [],
      total: 0,
      page,
      limit,
      totalPages: 0,
      hasNextPage: false,
    };
  }

  return {
    data: Array.isArray(response.data) ? response.data : [],
    total: typeof response.total === 'number' && response.total >= 0 ? response.total : 0,
    page: typeof response.page === 'number' && response.page >= 1 ? response.page : page,
    limit: typeof response.limit === 'number' && response.limit >= 1 ? response.limit : limit,
    totalPages: typeof response.totalPages === 'number' && response.totalPages >= 0 ? response.totalPages : 0,
    hasNextPage: typeof response.hasNextPage === 'boolean' ? response.hasNextPage : false,
  };
}

/**
 * Validates workflow data for creation
 */
function validateCreateWorkflowDto(dto: CreateWorkflowDto | null | undefined): CreateWorkflowDto {
  if (!dto) {
    throw new Error('Workflow data is required');
  }

  if (!dto.name || typeof dto.name !== 'string' || dto.name.trim().length === 0) {
    throw new Error('Workflow name is required');
  }

  if (dto.name.trim().length > 200) {
    throw new Error('Workflow name cannot exceed 200 characters');
  }

  if (!dto.workflowType || typeof dto.workflowType !== 'string') {
    throw new Error('Workflow type is required');
  }

  if (!dto.stages || !Array.isArray(dto.stages) || dto.stages.length === 0) {
    throw new Error('At least one workflow stage is required');
  }

  // Validate each stage
  dto.stages.forEach((stage: any, index: number) => {
    if (!stage.stageName || typeof stage.stageName !== 'string' || stage.stageName.trim().length === 0) {
      throw new Error(`Stage ${index + 1}: Name is required`);
    }
    if (typeof stage.stageOrder !== 'number' || stage.stageOrder < 1) {
      throw new Error(`Stage ${index + 1}: Valid order is required`);
    }
  });

  return {
    ...dto,
    name: dto.name.trim(),
    description: dto.description?.trim() || undefined,
  };
}

/**
 * Validates workflow data for update
 */
function validateUpdateWorkflowDto(dto: UpdateWorkflowDto | null | undefined): UpdateWorkflowDto {
  if (!dto) {
    throw new Error('Update data is required');
  }

  const sanitized: UpdateWorkflowDto = {};

  if (dto.name !== undefined) {
    if (typeof dto.name !== 'string' || dto.name.trim().length === 0) {
      throw new Error('Workflow name cannot be empty');
    }
    if (dto.name.trim().length > 200) {
      throw new Error('Workflow name cannot exceed 200 characters');
    }
    sanitized.name = dto.name.trim();
  }

  if (dto.description !== undefined) {
    sanitized.description = typeof dto.description === 'string' ? dto.description.trim() : undefined;
  }

  if (dto.isActive !== undefined) {
    if (typeof dto.isActive !== 'boolean') {
      throw new Error('isActive must be a boolean');
    }
    sanitized.isActive = dto.isActive;
  }

  if (dto.stages !== undefined) {
    if (!Array.isArray(dto.stages)) {
      throw new Error('Stages must be an array');
    }
    sanitized.stages = dto.stages;
  }

  if (dto.metadata !== undefined) {
    if (typeof dto.metadata !== 'object' || dto.metadata === null) {
      throw new Error('Metadata must be an object');
    }
    sanitized.metadata = dto.metadata;
  }

  return sanitized;
}

@Injectable({
  providedIn: 'root',
})
export class WorkflowService {
  private readonly api = inject(ApiService);

  getWorkflows(page = 1, limit = 10): Observable<PaginatedWorkflowsResponse> {
    const validated = validatePagination(page, limit);

    return this.api
      .getRaw<PaginatedWorkflowsResponse>('/workflows', {
        page: validated.page,
        limit: validated.limit,
      })
      .pipe(
        map((response) => ensureValidPaginatedResponse(response, validated.page, validated.limit)),
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : 'Failed to fetch workflows';
          return throwError(() => new Error(message));
        })
      );
  }

  getWorkflow(id: string): Observable<WorkflowResponseDto> {
    try {
      const validId = validateId(id, 'Workflow ID');

      return this.api.getRaw<WorkflowResponseDto>(`/workflows/${validId}`).pipe(
        map((response) => {
          if (!response) {
            throw new Error('Workflow not found');
          }
          // Response structure has stages inside definition
          return response;
        }),
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : `Failed to fetch workflow: ${id}`;
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }

  createWorkflow(dto: CreateWorkflowDto): Observable<WorkflowResponseDto> {
    try {
      const sanitizedDto = validateCreateWorkflowDto(dto);

      return this.api.postRaw<WorkflowResponseDto>('/workflows', sanitizedDto).pipe(
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : 'Failed to create workflow';
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }

  updateWorkflow(id: string, dto: UpdateWorkflowDto): Observable<WorkflowResponseDto> {
    try {
      const validId = validateId(id, 'Workflow ID');
      const sanitizedDto = validateUpdateWorkflowDto(dto);

      return this.api.patch<WorkflowResponseDto>(`/workflows/${validId}`, sanitizedDto).pipe(
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : `Failed to update workflow: ${id}`;
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }

  deleteWorkflow(id: string): Observable<void> {
    try {
      const validId = validateId(id, 'Workflow ID');

      return this.api.delete<void>(`/workflows/${validId}`).pipe(
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : `Failed to delete workflow: ${id}`;
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }

  validateWorkflow(dto: CreateWorkflowDto): Observable<WorkflowValidationResultDto> {
    try {
      const sanitizedDto = validateCreateWorkflowDto(dto);

      return this.api.post<WorkflowValidationResultDto>('/workflows/validate', sanitizedDto).pipe(
        map((response) => {
          if (!response) {
            return { isValid: false, errors: ['Validation failed: No response'] };
          }
          return {
            isValid: typeof response.isValid === 'boolean' ? response.isValid : false,
            errors: Array.isArray(response.errors) ? response.errors : [],
          };
        }),
        catchError((error: unknown) => {
          const message = error instanceof Error ? error.message : 'Failed to validate workflow';
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }

  toggleActive(id: string, isActive: boolean): Observable<WorkflowResponseDto> {
    try {
      const validId = validateId(id, 'Workflow ID');

      if (typeof isActive !== 'boolean') {
        return throwError(() => new Error('isActive must be a boolean value'));
      }

      return this.api.patch<WorkflowResponseDto>(`/workflows/${validId}`, { isActive }).pipe(
        catchError((error: unknown) => {
          const message =
            error instanceof Error ? error.message : `Failed to toggle active status for workflow: ${id}`;
          return throwError(() => new Error(message));
        })
      );
    } catch (error) {
      return throwError(() => error);
    }
  }
}
