import { XMLParser } from "fast-xml-parser";
import { RCIClient } from "../lib/client";
import type { ReservationResponse, ResponseHeader } from "../type";

export class RCIBooking {
  private client: <TResponse>(init?: RequestInit) => Promise<TResponse | null>;
  constructor() {
    const baseURL = process.env.RCI_TRX_URL!;
    if (!baseURL) {
      throw new Error("Missing RCI Transaction URL");
    }
    this.client = RCIClient(baseURL);
  }

  async createPropertyHold(
    credentials: {
      username: string;
      password: string;
    },
    payload: {
      sessionID: string;
      accommodationItem: {
        resortId: string;
        resortName: string;
        nbrOfBedrooms: number;
        availabilityInfo: {
          systemId: {
            inventoryType: number | string;
            inventoryId: string;
          };
          checkInDate: string;
          checkOutDate: string;
          unitCost: {
            value: number;
            currency: string;
          };
        };
      };
    },
  ) {
    try {
      const bookingInfo = payload.accommodationItem.availabilityInfo;
      const body = `
        <requestEnvelope>
          	<requestHeader>
           		<controlData>
          			<clientName>XMLBusinessPartnerChannel</clientName>
          			<userID>${credentials.username}</userID>
          			<password>${credentials.password}</password>
           		</controlData>
           		<processData>
          			<operationName>hold</operationName>
           		</processData>
          	</requestHeader>
          	<ReservationRequest>
             <sessionToken>
          			<sessionId>${payload.sessionID.toString()}</sessionId>
             </sessionToken>
           	<accommodationItem>
          		  <resortId>${payload.accommodationItem.resortId.toString()}</resortId>
            		<resortName><![CDATA[${payload.accommodationItem.resortId}-${payload.accommodationItem.resortName}]]></resortName>
            		<nbrOfBedrooms>${payload.accommodationItem.nbrOfBedrooms}</nbrOfBedrooms>
            		<bookingInfo>
           			<systemId>
            				<inventoryType>${bookingInfo.systemId.inventoryType}</inventoryType>
             		  <inventoryId>${bookingInfo.systemId.inventoryId.toString()}</inventoryId>
           			</systemId>
           			<checkInDate>${bookingInfo.checkInDate}</checkInDate>
           			<checkOutDate>${bookingInfo.checkOutDate}</checkOutDate>
           			<charge>
          				  <value>${bookingInfo.unitCost.value}.00</value>
            				<currency>${bookingInfo.unitCost.currency}</currency>
           			</charge>
            		</bookingInfo>
           	</accommodationItem>
          	</ReservationRequest>
        </requestEnvelope>
        `;

      const response = await this.client<string>({
        method: "POST",
        body,
      });
      if (!response) {
        return null;
      }
      const parser = new XMLParser();
      const parsedResponse = parser.parse(response) as {
        responseEnvelope: {
          responseHeader: ResponseHeader;
          ReservationResponse: ReservationResponse;
        };
      };
      return parsedResponse;
    } catch (err) {
      throw err instanceof Error ? err : new Error(String(err));
    }
  }
  async releasePropertyHold(
    credentials: {
      username: string;
      password: string;
    },
    payload: {
      inventoryType: string;
      referenceNumber: string;
    },
  ) {
    try {
      const response = await this.client<string>({
        method: "POST",
        body: `
        <requestEnvelope>
          <requestHeader>
            <controlData>
              <clientName>XMLBusinessPartnerChannel</clientName>
              <userID>${credentials.username}</userID>
              <password>${credentials.password}</password>
            </controlData>
            <processData>
              <operationName>release</operationName>
            </processData>
          </requestHeader>
          <ReleaseRequest>
            <reservationToken>
              <inventoryType>${payload.inventoryType}</inventoryType>
              <referenceNumber>${payload.referenceNumber}</referenceNumber>
            </reservationToken>
          </ReleaseRequest>
        </requestEnvelope>
       `,
      });
      if (!response) {
        return null;
      }
      const parser = new XMLParser();
      const parsedResponse = parser.parse(response) as {
        responseEnvelope: {
          responseHeader: ResponseHeader;
          // SearchResponse: ResortsSearchResponse;
        };
      };
      return parsedResponse;
    } catch (err) {
      throw err instanceof Error ? err : new Error(String(err));
    }
  }

  async getPropertyBookingActivity(
    credentials: {
      username: string;
      password: string;
    },
    payload: {
      inventoryType: string;
      referenceNumber: string;
      startDate: string;
      endDate: string;
    },
  ) {
    try {
      const response = await this.client<string>({
        method: "POST",
        body: `
        <requestEnvelope>
         	<requestHeader>
          		<controlData>
         			  <clientName>XMLBusinessPartnerChannel</clientName>
           			<userID>${credentials.username}</userID>
           			<password>${credentials.password}</password>
          		</controlData>
          		<processData>
         			  <operationName>retrieveActivity</operationName>
              </processData>
         	</requestHeader>
         	<ActivityRequest>
            <reservationToken>
         			<inventoryType>${payload.inventoryType}</inventoryType>
         			<referenceNumber>${payload.referenceNumber}</referenceNumber>
        		</reservationToken>
            <onHoldActivity fetch="true"/>
            <confirmedActivity fetch="false"/>
            <cancelledActivity fetch="false"/>
            <startDate>${payload.startDate}</startDate>
            <endDate>${payload.endDate}</endDate>
            <dateFlag>checkinDate</dateFlag>
         	</ActivityRequest>
        </requestEnvelope>
       `,
      });
      if (!response) {
        return null;
      }
      const parser = new XMLParser();
      const parsedResponse = parser.parse(response) as {
        responseEnvelope: {
          responseHeader: ResponseHeader;
          // SearchResponse: ResortsSearchResponse;
        };
      };
      console.log(JSON.stringify(parsedResponse));
      return parsedResponse;
    } catch (err) {
      throw err instanceof Error ? err : new Error(String(err));
    }
  }

  async confirmPropertyHold(
    credentials: {
      username: string;
      password: string;
    },
    payload: {
      inventoryType: string;
      referenceNumber: string;
    },
  ) {
    try {
      const response = await this.client<string>({
        method: "POST",
        body: `
        <requestEnvelope>
          <requestHeader>
          		<controlData>
         			  <clientName>XMLBusinessPartnerChannel</clientName>
         			  <userID>${credentials.username}</userID>
         			  <password>${credentials.password}</password>
          		</controlData>
          		<processData>
         			  <operationName>confirmHold</operationName>
          		</processData>
         	</requestHeader>
         	<ConfirmRequest>
          		<reservationToken>
         			  <inventoryType>${payload.inventoryType}</inventoryType>
           			<referenceNumber>${payload.referenceNumber}</referenceNumber>
          		</reservationToken>
         	</ConfirmRequest>
        </requestEnvelope>
       `,
      });
      if (!response) {
        return null;
      }
      const parser = new XMLParser();
      const parsedResponse = parser.parse(response) as {
        responseEnvelope: {
          responseHeader: ResponseHeader;
          ReservationResponse: ReservationResponse;
        };
      };
      return parsedResponse;
    } catch (err) {
      throw err instanceof Error ? err : new Error(String(err));
    }
  }

  async cancelPropertyBooking(
    credentials: {
      username: string;
      password: string;
    },
    payload: {
      inventoryType: string;
      referenceNumber: string;
    },
  ) {
    try {
      const response = await this.client<string>({
        method: "POST",
        body: `
        <requestEnvelope>
         	<requestHeader>
            <controlData>
         			<clientName>XMLBusinessPartnerChannel</clientName>
           	  <userID>${credentials.username}</userID>
             	<password>${credentials.password}</password>
            </controlData>
            <processData>
         			<operationName>cancel</operationName>
            </processData>
         	</requestHeader>
         	<CancelRequest>
          		<reservationToken>
         			<inventoryType>${payload.inventoryType}</inventoryType>
         			<referenceNumber>${payload.referenceNumber}</referenceNumber>
          		</reservationToken>
         	</CancelRequest>
        </requestEnvelope>
       `,
      });
      if (!response) {
        return null;
      }
      const parser = new XMLParser();
      const parsedResponse = parser.parse(response) as {
        responseEnvelope: {
          responseHeader: ResponseHeader;
          ReservationResponse: ReservationResponse;
        };
      };
      return parsedResponse;
    } catch (err) {
      throw err instanceof Error ? err : new Error(String(err));
    }
  }
}
