/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import { TestBed } from "@angular/core/testing";
import { WorkflowResultExportService } from "./workflow-result-export.service";
import { HttpClientTestingModule } from "@angular/common/http/testing";
import { WorkflowWebsocketService } from "../workflow-websocket/workflow-websocket.service";
import { WorkflowActionService } from "../workflow-graph/model/workflow-action.service";
import { NotificationService } from "../../../common/service/notification/notification.service";
import { ExecuteWorkflowService } from "../execute-workflow/execute-workflow.service";
import { WorkflowResultService } from "../workflow-result/workflow-result.service";
import { of } from "rxjs";
import { ExecutionState } from "../../types/execute-workflow.interface";
import { DownloadService } from "src/app/dashboard/service/user/download/download.service";
import { DatasetService } from "../../../dashboard/service/user/dataset/dataset.service";
import { commonTestProviders } from "../../../common/testing/test-utils";

describe("WorkflowResultExportService", () => {
  let service: WorkflowResultExportService;
  let workflowWebsocketServiceSpy: jasmine.SpyObj<WorkflowWebsocketService>;
  let workflowActionServiceSpy: jasmine.SpyObj<WorkflowActionService>;
  let notificationServiceSpy: jasmine.SpyObj<NotificationService>;
  let executeWorkflowServiceSpy: jasmine.SpyObj<ExecuteWorkflowService>;
  let workflowResultServiceSpy: jasmine.SpyObj<WorkflowResultService>;
  let downloadServiceSpy: jasmine.SpyObj<DownloadService>;
  let datasetServiceSpy: jasmine.SpyObj<DatasetService>;

  let jointGraphWrapperSpy: jasmine.SpyObj<any>;
  let texeraGraphSpy: jasmine.SpyObj<any>;

  beforeEach(() => {
    // Create spies for the required services
    jointGraphWrapperSpy = jasmine.createSpyObj("JointGraphWrapper", [
      "getCurrentHighlightedOperatorIDs",
      "getJointOperatorHighlightStream",
      "getJointOperatorUnhighlightStream",
    ]);
    jointGraphWrapperSpy.getCurrentHighlightedOperatorIDs.and.returnValue([]);
    jointGraphWrapperSpy.getJointOperatorHighlightStream.and.returnValue(of());
    jointGraphWrapperSpy.getJointOperatorUnhighlightStream.and.returnValue(of());

    texeraGraphSpy = jasmine.createSpyObj("TexeraGraph", [
      "getAllOperators",
      "getOperatorAddStream",
      "getOperatorDeleteStream",
      "getOperatorPropertyChangeStream",
      "getLinkAddStream",
      "getLinkDeleteStream",
      "getDisabledOperatorsChangedStream",
      "getAllLinks",
    ]);
    texeraGraphSpy.getAllOperators.and.returnValue([]);
    texeraGraphSpy.getOperatorAddStream.and.returnValue(of());
    texeraGraphSpy.getOperatorDeleteStream.and.returnValue(of());
    texeraGraphSpy.getOperatorPropertyChangeStream.and.returnValue(of());
    texeraGraphSpy.getLinkAddStream.and.returnValue(of());
    texeraGraphSpy.getLinkDeleteStream.and.returnValue(of());
    texeraGraphSpy.getDisabledOperatorsChangedStream.and.returnValue(of());
    texeraGraphSpy.getAllLinks.and.returnValue([]);

    const wsSpy = jasmine.createSpyObj("WorkflowWebsocketService", ["subscribeToEvent", "send"]);
    wsSpy.subscribeToEvent.and.returnValue(of()); // Return an empty observable
    const waSpy = jasmine.createSpyObj("WorkflowActionService", [
      "getJointGraphWrapper",
      "getTexeraGraph",
      "getWorkflow",
    ]);
    waSpy.getJointGraphWrapper.and.returnValue(jointGraphWrapperSpy);
    waSpy.getTexeraGraph.and.returnValue(texeraGraphSpy);
    waSpy.getWorkflow.and.returnValue({ wid: "workflow1", name: "Test Workflow" });

    const ntSpy = jasmine.createSpyObj("NotificationService", ["success", "error", "loading"]);
    const ewSpy = jasmine.createSpyObj("ExecuteWorkflowService", ["getExecutionStateStream", "getExecutionState"]);
    ewSpy.getExecutionStateStream.and.returnValue(of({ previous: {}, current: { state: ExecutionState.Completed } }));
    ewSpy.getExecutionState.and.returnValue({ state: ExecutionState.Completed });

    const wrSpy = jasmine.createSpyObj("WorkflowResultService", [
      "hasAnyResult",
      "getResultService",
      "getPaginatedResultService",
    ]);
    const downloadSpy = jasmine.createSpyObj("DownloadService", ["downloadOperatorsResult"]);
    downloadSpy.downloadOperatorsResult.and.returnValue(of(new Blob()));

    const datasetSpy = jasmine.createSpyObj("DatasetService", ["retrieveAccessibleDatasets"]);
    datasetSpy.retrieveAccessibleDatasets.and.returnValue(of([]));

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        WorkflowResultExportService,
        { provide: WorkflowWebsocketService, useValue: wsSpy },
        { provide: WorkflowActionService, useValue: waSpy },
        { provide: NotificationService, useValue: ntSpy },
        { provide: ExecuteWorkflowService, useValue: ewSpy },
        { provide: WorkflowResultService, useValue: wrSpy },
        { provide: DownloadService, useValue: downloadSpy },
        { provide: DatasetService, useValue: datasetSpy },
        ...commonTestProviders,
      ],
    });

    // Inject the service and spies
    service = TestBed.inject(WorkflowResultExportService);
    workflowWebsocketServiceSpy = TestBed.inject(WorkflowWebsocketService) as jasmine.SpyObj<WorkflowWebsocketService>;
    workflowActionServiceSpy = TestBed.inject(WorkflowActionService) as jasmine.SpyObj<WorkflowActionService>;
    notificationServiceSpy = TestBed.inject(NotificationService) as jasmine.SpyObj<NotificationService>;
    executeWorkflowServiceSpy = TestBed.inject(ExecuteWorkflowService) as jasmine.SpyObj<ExecuteWorkflowService>;
    workflowResultServiceSpy = TestBed.inject(WorkflowResultService) as jasmine.SpyObj<WorkflowResultService>;
    downloadServiceSpy = TestBed.inject(DownloadService) as jasmine.SpyObj<DownloadService>;
    datasetServiceSpy = TestBed.inject(DatasetService) as jasmine.SpyObj<DatasetService>;
  });

  it("should be created", () => {
    expect(service).toBeTruthy();
  });
});
