import { describe, it, expect } from "vitest";
import {
  resolveDisplayStage,
  classifyDeals,
  computeDampMouldRisk,
  computeFunnelStages,
  computeProjectProgress,
  computeLiveTrackerData,
} from "./transforms";
import type { HubspotDeal, ClassifiedDeal } from "./types";

function makeDeal(overrides: Partial<HubspotDeal> = {}): HubspotDeal {
  return {
    id: "1",
    dealId: "deal-1",
    dealname: "Test Property",
    dealstage: null,
    companyId: null,
    projectCode: null,
    landlordPropertyId: null,
    uprn: null,
    outcome: null,
    outcomeNotes: null,
    majorConditionIssueDescription: null,
    majorConditionIssuePhotos: null,
    majorConditionIssuePhotosS3: null,
    coordinationStatus: null,
    designStatus: null,
    bookingStatus: null,
    pashubLink: null,
    sharepointLink: null,
    dampMouldFlag: null,
    dampMouldAndRepairComments: null,
    preSapScore: null,
    coordinator: null,
    ioeV1Date: null,
    ioeV2Date: null,
    ioeV3Date: null,
    proposedMeasures: null,
    approvedPackage: null,
    designer: null,
    designDate: null,
    actualMeasuresInstalled: null,
    installer: null,
    installerHandover: null,
    lodgementStatus: null,
    measuresLodgementDate: null,
    fullLodgementDate: null,
    confirmedSurveyDate: null,
    confirmedSurveyTime: null,
    surveyedDate: null,
    designType: null,
    eiScore: null,
    eiScorePotential: null,
    epcSapScore: null,
    potentialPostSapScoreDropdown: null,
    epcPrn: null,
    surveyType: null,
    measuresForPibiOrdered: null,
    pibiOrderDate: null,
    pibiCompletedDate: null,
    propertyHaltedDate: null,
    propertyHaltedReason: null,
    technicalApprovedMeasuresForInstall: null,
    domnaSurveyType: null,
    domnaSurveyDate: null,
    batch: null,
    batchDescription: null,
    planningAuthority: null,
    designatedArea: null,
    article4PdRights: null,
    listedBuilding: null,
    designConstraints: null,
    planningComments: null,
    planningStatus: null,
    planningSuggestedApproach: null,
    coordinationComments: null,
    domnasurveyRequired: null,
    createdAt: new Date(),
    updatedAt: new Date(),
    ...overrides,
  };
}

function makeClassified(overrides: Partial<ClassifiedDeal> = {}): ClassifiedDeal {
  return { ...makeDeal(overrides), displayStage: "Scope & Planning", ...overrides };
}

// -----------------------------------------------------------------------
// resolveDisplayStage
// -----------------------------------------------------------------------

describe("resolveDisplayStage — direct STAGE_ID_MAP lookups", () => {
  it("returns Scope & Planning for a backlog stage ID", () => {
    expect(resolveDisplayStage(makeDeal({ dealstage: "1617223910" }))).toBe("Scope & Planning");
  });

  it("returns Booking in Progress for a bookings stage ID", () => {
    expect(resolveDisplayStage(makeDeal({ dealstage: "3589581001" }))).toBe("Booking in Progress");
  });

  it("returns Assessment in Progress for a survey-in-progress stage ID", () => {
    expect(resolveDisplayStage(makeDeal({ dealstage: "1617223913" }))).toBe("Assessment in Progress");
  });

  it("returns Queries for a known queries stage ID", () => {
    expect(resolveDisplayStage(makeDeal({ dealstage: "2663668937" }))).toBe("Queries");
  });

  it("falls through to AFTER_ASSESSMENT path when dealstage is null", () => {
    // null dealstage → AFTER_ASSESSMENT → no coord/design status → Coordination in Progress
    expect(resolveDisplayStage(makeDeal({ dealstage: null }))).toBe("Coordination in Progress");
  });

  it("falls through to AFTER_ASSESSMENT path for an unrecognised stage ID", () => {
    expect(resolveDisplayStage(makeDeal({ dealstage: "9999999999" }))).toBe("Coordination in Progress");
  });
});

describe("resolveDisplayStage — RA ISSUE override on non-AFTER_ASSESSMENT stages", () => {
  it("overrides Scope & Planning to Queries when coordinationStatus is RA ISSUE", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: "1617223910", coordinationStatus: "RA ISSUE" }))
    ).toBe("Queries");
  });

  it("overrides Assessment in Progress to Queries when coordinationStatus is RA ISSUE", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: "1617223913", coordinationStatus: "RA ISSUE" }))
    ).toBe("Queries");
  });

  it("is case-insensitive for RA ISSUE check", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: "1617223913", coordinationStatus: "ra issue" }))
    ).toBe("Queries");
  });

  it("does NOT override Booking in Progress with RA ISSUE (only Scope & Planning and Assessment in Progress)", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: "3589581001", coordinationStatus: "RA ISSUE" }))
    ).toBe("Booking in Progress");
  });
});

describe("resolveDisplayStage — Removed from Bookings", () => {
  it("classifies as Removed from Bookings when bookingStatus is Do Not Book and no outcome", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: "Do Not Book",
        outcome: null,
      }))
    ).toBe("Removed from Bookings");
  });

  it("classifies as Removed from Bookings when bookingStatus is Do Not Book and outcome is a non-successful survey outcome", () => {
    // Tenant Refusal is a non-successful outcome; with DNB the property is removed from bookings,
    // not lingering in the normal pipeline.
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: "Do Not Book",
        outcome: "Tenant Refusal",
      }))
    ).toBe("Removed from Bookings");
  });

  it("falls back to normal stage resolution when bookingStatus is Do Not Book but outcome is Surveyed", () => {
    // Real survey history overrides DNB — the property stays in the normal pipeline.
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: "Do Not Book",
        outcome: "Surveyed",
      }))
    ).toBe("Scope & Planning");
  });

  it("falls back to normal stage resolution when bookingStatus is Do Not Book but outcome is Surveyed - Pending Upload", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: "Do Not Book",
        outcome: "Surveyed - Pending Upload",
      }))
    ).toBe("Scope & Planning");
  });

  it("falls back to normal stage resolution when bookingStatus is Do Not Book but outcome is EPC Completed", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: "Do Not Book",
        outcome: "EPC Completed",
      }))
    ).toBe("Scope & Planning");
  });

  it("classifies as Removed from Bookings for Not Viable + Do Not Book even when the dealstage maps to Queries", () => {
    // "1887735998" is the Not Viable dealstage, which normally maps to "Queries".
    // With DNB + a non-successful outcome, Removed from Bookings takes precedence over the Queries mapping.
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1887735998",
        bookingStatus: "Do Not Book",
        outcome: "Not Viable",
      }))
    ).toBe("Removed from Bookings");
  });

  it("does not classify as Removed from Bookings when an outcome is set but bookingStatus is null", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223910",
        bookingStatus: null,
        outcome: "Surveyed",
      }))
    ).toBe("Scope & Planning");
  });
});

describe("resolveDisplayStage — Removed from Program", () => {
  it("classifies as Removed from Program when batch is 'Removed from Program' regardless of dealstage", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "1617223913",
        batch: "Removed from Program",
      }))
    ).toBe("Removed from Program");
  });

  it("Removed from Program takes precedence over Removed from Bookings", () => {
    expect(
      resolveDisplayStage(makeDeal({
        batch: "Removed from Program",
        bookingStatus: "Do Not Book",
        outcome: null,
      }))
    ).toBe("Removed from Program");
  });
});

describe("resolveDisplayStage — precedence between new stages and existing classification", () => {
  it("Removed from Bookings takes precedence over a Queries dealstage", () => {
    // "2663668937" is a Queries-mapped dealstage; without Do Not Book it'd resolve to "Queries"
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: "2663668937",
        bookingStatus: "Do Not Book",
        outcome: null,
      }))
    ).toBe("Removed from Bookings");
  });
});

describe("resolveDisplayStage — AFTER_ASSESSMENT sub-classification", () => {
  const AFTER_ASSESSMENT_STAGE = "3948185842";

  it("returns Queries when coordinationStatus is RA ISSUE", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: AFTER_ASSESSMENT_STAGE, coordinationStatus: "RA ISSUE" }))
    ).toBe("Queries");
  });

  it("returns Coordination in Progress by default (no special status)", () => {
    expect(
      resolveDisplayStage(makeDeal({ dealstage: AFTER_ASSESSMENT_STAGE, coordinationStatus: null, designStatus: null }))
    ).toBe("Coordination in Progress");
  });

  it("returns Design in Progress when coord is IOE/MTP COMPLETE but design not yet uploaded", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: AFTER_ASSESSMENT_STAGE,
        coordinationStatus: "(V1) IOE/MTP COMPLETE",
        designStatus: "IN PROGRESS",
      }))
    ).toBe("Design in Progress");
  });

  it("returns Design in Progress for V2 IOE/MTP COMPLETE variant", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: AFTER_ASSESSMENT_STAGE,
        coordinationStatus: "(V2) IOE/MTP COMPLETE",
        designStatus: null,
      }))
    ).toBe("Design in Progress");
  });

  it("returns Design in Progress for V3 IOE/MTP COMPLETE variant", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: AFTER_ASSESSMENT_STAGE,
        coordinationStatus: "(V3) IOE/MTP COMPLETE",
        designStatus: null,
      }))
    ).toBe("Design in Progress");
  });

  it("is case-insensitive for coord/design status checks", () => {
    expect(
      resolveDisplayStage(makeDeal({
        dealstage: AFTER_ASSESSMENT_STAGE,
        coordinationStatus: "(v1) ioe/mtp complete",
        designStatus: "uploaded",
      }))
    ).toBe("Installation in Progress"); // POST_DESIGN, no install fields set
  });
});

describe("resolveDisplayStage — POST_DESIGN sub-classification (design UPLOADED)", () => {
  const AFTER_ASSESSMENT_STAGE = "3948185842";

  function makePostDesignDeal(overrides: Partial<HubspotDeal> = {}): HubspotDeal {
    return makeDeal({
      dealstage: AFTER_ASSESSMENT_STAGE,
      coordinationStatus: "(V1) IOE/MTP COMPLETE",
      designStatus: "UPLOADED",
      ...overrides,
    });
  }

  it("returns Installation in Progress when no install fields are set", () => {
    expect(resolveDisplayStage(makePostDesignDeal())).toBe("Installation in Progress");
  });

  it("returns Installation Complete when actualMeasuresInstalled is set", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({ actualMeasuresInstalled: "Insulation" }))
    ).toBe("Installation Complete");
  });

  it("returns Installation Complete when installerHandover is set", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({ installerHandover: "2024-01-01" }))
    ).toBe("Installation Complete");
  });

  it("returns At Lodgement when lodgementStatus is set", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({ lodgementStatus: "Submitted" }))
    ).toBe("At Lodgement");
  });

  it("returns At Post Survey when measuresLodgementDate is set", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({ measuresLodgementDate: new Date() }))
    ).toBe("At Post Survey");
  });

  it("returns Project Complete when fullLodgementDate is set", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({ fullLodgementDate: new Date() }))
    ).toBe("Project Complete");
  });

  it("fullLodgementDate takes precedence over measuresLodgementDate and lodgementStatus", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({
        fullLodgementDate: new Date(),
        measuresLodgementDate: new Date(),
        lodgementStatus: "Submitted",
      }))
    ).toBe("Project Complete");
  });

  it("measuresLodgementDate takes precedence over lodgementStatus", () => {
    expect(
      resolveDisplayStage(makePostDesignDeal({
        measuresLodgementDate: new Date(),
        lodgementStatus: "Submitted",
      }))
    ).toBe("At Post Survey");
  });
});

// -----------------------------------------------------------------------
// classifyDeals
// -----------------------------------------------------------------------

describe("classifyDeals", () => {
  it("adds displayStage to each deal", () => {
    const deals = [
      makeDeal({ dealstage: "1617223910" }),
      makeDeal({ dealstage: "1617223913" }),
    ];
    const result = classifyDeals(deals);
    expect(result[0].displayStage).toBe("Scope & Planning");
    expect(result[1].displayStage).toBe("Assessment in Progress");
  });

  it("returns an empty array for no deals", () => {
    expect(classifyDeals([])).toEqual([]);
  });

  it("preserves all original deal fields", () => {
    const deal = makeDeal({ dealId: "abc-123", dealname: "Test" });
    const [result] = classifyDeals([deal]);
    expect(result.dealId).toBe("abc-123");
    expect(result.dealname).toBe("Test");
  });
});

// -----------------------------------------------------------------------
// computeDampMouldRisk
// -----------------------------------------------------------------------

describe("computeDampMouldRisk", () => {
  it("counts survey flags from majorConditionIssuePhotosS3", () => {
    const deals = [
      makeClassified({ majorConditionIssuePhotosS3: "s3://bucket/file.jpg" }),
      makeClassified({ majorConditionIssuePhotosS3: null }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.surveyFlagCount).toBe(1);
  });

  it("counts coordinator flags from dampMouldFlag", () => {
    const deals = [
      makeClassified({ dampMouldFlag: "Yes" }),
      makeClassified({ dampMouldFlag: null }),
      makeClassified({ dampMouldFlag: "Yes" }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.coordinatorFlagCount).toBe(2);
  });

  it("ignores a growth flag of 'No' when there is no comment", () => {
    const deals = [
      makeClassified({ dampMouldFlag: "No", dampMouldAndRepairComments: null }),
      makeClassified({ dampMouldFlag: "no", dampMouldAndRepairComments: "  " }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.coordinatorFlagCount).toBe(0);
  });

  it("treats a 'yes' growth flag case-insensitively, ignoring whitespace", () => {
    const deals = [
      makeClassified({ dampMouldFlag: "yes" }),
      makeClassified({ dampMouldFlag: " Yes " }),
      makeClassified({ dampMouldFlag: "YES" }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.coordinatorFlagCount).toBe(3);
  });

  it("counts a deal with a comment but no growth flag as coordinator-flagged", () => {
    const deals = [
      makeClassified({
        dampMouldFlag: null,
        dampMouldAndRepairComments: "Mould in NE bedroom corner",
      }),
      makeClassified({ dampMouldFlag: null, dampMouldAndRepairComments: null }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.coordinatorFlagCount).toBe(1);
    expect(result.coordinatorFlagDeals).toHaveLength(1);
  });

  it("counts deals flagged at both stages independently", () => {
    const deals = [
      makeClassified({ majorConditionIssuePhotosS3: "s3://x", dampMouldFlag: "Yes" }),
      makeClassified({ majorConditionIssuePhotosS3: "s3://y", dampMouldFlag: null }),
      makeClassified({ majorConditionIssuePhotosS3: null, dampMouldFlag: "Yes" }),
    ];
    const result = computeDampMouldRisk(deals);
    expect(result.surveyFlagCount).toBe(2);
    expect(result.coordinatorFlagCount).toBe(2);
    expect(result.bothFlaggedCount).toBe(1);
  });

  it("returns zero counts for empty deals", () => {
    const result = computeDampMouldRisk([]);
    expect(result.surveyFlagCount).toBe(0);
    expect(result.coordinatorFlagCount).toBe(0);
    expect(result.bothFlaggedCount).toBe(0);
    expect(result.totalDeals).toBe(0);
  });
});

// -----------------------------------------------------------------------
// computeFunnelStages
// -----------------------------------------------------------------------

describe("computeFunnelStages", () => {
  it("excludes Queries deals from counts and percentages", () => {
    const deals = [
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Queries" }),
    ];
    const funnel = computeFunnelStages(deals);
    const scopeEntry = funnel.find((f) => f.stage === "Scope & Planning")!;
    expect(scopeEntry.currentPct).toBe(100); // 1 out of 1 non-query
  });

  it("returns 0 percentages when all deals are Queries", () => {
    const deals = [makeClassified({ displayStage: "Queries" })];
    const funnel = computeFunnelStages(deals);
    funnel.forEach((f) => {
      expect(f.currentPct).toBe(0);
      expect(f.cumulativePct).toBe(0);
    });
  });

  it("cumulative count includes all deals at or beyond a given stage", () => {
    const deals = [
      makeClassified({ displayStage: "Installation in Progress" }),
      makeClassified({ displayStage: "Installation Complete" }),
      makeClassified({ displayStage: "Project Complete" }),
    ];
    const funnel = computeFunnelStages(deals);
    const installEntry = funnel.find((f) => f.stage === "Installation in Progress")!;
    // All 3 deals are at or beyond "Installation in Progress"
    expect(installEntry.cumulativeCount).toBe(3);
    expect(installEntry.currentCount).toBe(1);
  });

  it("returns an entry for every stage in STAGE_ORDER", () => {
    const funnel = computeFunnelStages([]);
    expect(funnel.length).toBe(10); // STAGE_ORDER has 10 entries
  });

  it("excludes Removed from Bookings and Removed from Program from counts and percentages", () => {
    const deals = [
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Removed from Bookings" }),
      makeClassified({ displayStage: "Removed from Program" }),
    ];
    const funnel = computeFunnelStages(deals);
    const scopeEntry = funnel.find((f) => f.stage === "Scope & Planning")!;
    expect(scopeEntry.currentPct).toBe(100); // 1 out of 1 in-pipeline deal
  });
});

// -----------------------------------------------------------------------
// computeProjectProgress
// -----------------------------------------------------------------------

describe("computeProjectProgress", () => {
  it("excludes Queries from nonQueryTotal but includes them in totalDeals", () => {
    const deals = [
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Queries" }),
    ];
    const result = computeProjectProgress(deals);
    expect(result.totalDeals).toBe(2);
    expect(result.nonQueryTotal).toBe(1);
    expect(result.queriesDeals).toHaveLength(1);
  });

  it("computes completedPercentage as fraction of non-query total", () => {
    const deals = [
      makeClassified({ displayStage: "Project Complete" }),
      makeClassified({ displayStage: "Project Complete" }),
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Queries" }), // excluded from denominator
    ];
    const result = computeProjectProgress(deals);
    expect(result.completedCount).toBe(2);
    expect(result.completedPercentage).toBeCloseTo(66.67, 1);
    expect(result.nonQueryTotal).toBe(3);
  });

  it("returns 0 percentages when there are no non-query deals", () => {
    const deals = [makeClassified({ displayStage: "Queries" })];
    const result = computeProjectProgress(deals);
    expect(result.completedPercentage).toBe(0);
    result.stageProgress.forEach((s) => expect(s.percentage).toBe(0));
  });

  it("returns correct stage counts in stageProgress", () => {
    const deals = [
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Assessment in Progress" }),
    ];
    const result = computeProjectProgress(deals);
    const scopeItem = result.stageProgress.find((s) => s.stage === "Scope & Planning")!;
    const assessItem = result.stageProgress.find((s) => s.stage === "Assessment in Progress")!;
    expect(scopeItem.count).toBe(2);
    expect(assessItem.count).toBe(1);
  });

  it("stageProgress does not include a Queries entry", () => {
    const result = computeProjectProgress([makeClassified({ displayStage: "Queries" })]);
    expect(result.stageProgress.find((s) => s.stage === "Queries")).toBeUndefined();
  });

  it("excludes Removed from Bookings and Removed from Program from nonQueryTotal", () => {
    const deals = [
      makeClassified({ displayStage: "Scope & Planning" }),
      makeClassified({ displayStage: "Removed from Bookings" }),
      makeClassified({ displayStage: "Removed from Program" }),
    ];
    const result = computeProjectProgress(deals);
    expect(result.totalDeals).toBe(3);
    expect(result.nonQueryTotal).toBe(1);
  });
});

// -----------------------------------------------------------------------
// computeLiveTrackerData
// -----------------------------------------------------------------------

describe("computeLiveTrackerData", () => {
  it("returns a single project entry and no __ALL__ when all deals share one project code", () => {
    const deals = [
      makeDeal({ projectCode: "PROJ-A", dealstage: "1617223910" }),
      makeDeal({ projectCode: "PROJ-A", dealstage: "1617223913" }),
    ];
    const result = computeLiveTrackerData(deals);
    expect(result.projects).toHaveLength(1);
    expect(result.projects[0].projectCode).toBe("PROJ-A");
  });

  it("prepends a synthetic __ALL__ entry when deals span multiple project codes", () => {
    const deals = [
      makeDeal({ projectCode: "PROJ-A", dealstage: "1617223910" }),
      makeDeal({ projectCode: "PROJ-B", dealstage: "1617223913" }),
    ];
    const result = computeLiveTrackerData(deals);
    expect(result.projects[0].projectCode).toBe("__ALL__");
    expect(result.projects).toHaveLength(3); // __ALL__ + PROJ-A + PROJ-B
  });

  it("__ALL__ progress covers all deals across project codes", () => {
    const deals = [
      makeDeal({ projectCode: "PROJ-A", dealstage: "1617223910" }),
      makeDeal({ projectCode: "PROJ-B", dealstage: "1617223913" }),
    ];
    const result = computeLiveTrackerData(deals);
    expect(result.projects[0].progress.totalDeals).toBe(2);
  });

  it("totalDeals is the count of all classified deals", () => {
    const deals = [
      makeDeal({ projectCode: "PROJ-A" }),
      makeDeal({ projectCode: "PROJ-A" }),
      makeDeal({ projectCode: "PROJ-A" }),
    ];
    expect(computeLiveTrackerData(deals).totalDeals).toBe(3);
  });

  it("filters majorConditionDeals by the major condition stage ID", () => {
    const deals = [
      makeDeal({ dealstage: "3061261536" }), // MAJOR_CONDITION_STAGE_ID
      makeDeal({ dealstage: "1617223910" }),
    ];
    const result = computeLiveTrackerData(deals);
    expect(result.majorConditionDeals).toHaveLength(1);
    expect(result.majorConditionDeals[0].dealstage).toBe("3061261536");
  });

  it("groups deals without a projectCode under Unknown Project", () => {
    const deals = [makeDeal({ projectCode: null })];
    const result = computeLiveTrackerData(deals);
    expect(result.projects[0].projectCode).toBe("Unknown Project");
  });

  it("returns empty projects and zero counts for no input deals", () => {
    const result = computeLiveTrackerData([]);
    expect(result.projects).toHaveLength(0);
    expect(result.totalDeals).toBe(0);
    expect(result.majorConditionDeals).toHaveLength(0);
  });
});
