// Interencheres.js
'use strict';
const { config } = require('../../../config');
const {Scraper} = require('../Scraper');
const DrouotData = require('./DrouotData');

class Drouot extends Scraper {

  constructor(Url) {
    super(Url);

    this.platformData = new DrouotData();
    
    this.platformData.getUrlInfo(Url).then((data) => {      
      if(data.lotID == 0 && data.saleID == 0){
        throw new Error('Invalid URL');
      }
    });

    this._Name = 'drouot'
    this._PAGE_MAIN = "https://drouot.com/fr/"
    this._PAGE_LOGIN = "https://auth.drouot.com/login"

    this._USER = "jp.ranu@cogip.de"
    this._PWD = "LYPYRKDUsSMH5BaWQxvH#"
    this._PATH_SESSION_FILE = ".session/session_drouot.json"
    this._PATH_PROTOBUF_FILE = "./AuctionServices/Scraper/Drouot/drouot.proto"
    this._BROWSER_TOOL = "playwrightBrowser"
  }

  getPictures = async ({ page, data}) => {

    const PictList = await this.platformData.getPictures(page, this.Url);
    console.log('PictList : '+PictList)
    return PictList    
  }

  getLotInfos = async ({ page, data}) => {
    
      console.log("getLotInfos "+this._Name+":  "+this.Url)
     
      // Navigate the page to a URL            
      await page.goto(this.Url);           
            
      let idLot = await this.platformData.getLotID(this.Url);
      console.log('idLot : '+idLot)
      
      // ## LotNumber      
      let lotNumber = await this.platformData.getLotNumber(page);      
      console.log('lotNumber : '+lotNumber)

      // ## Title
      let title = await this.platformData.getLotTitle(page);
      console.log('title : '+title)

      // ## Estimate
      let {EstimateLow, EstimateHigh} = await this.platformData.getEstimate(page);
      console.log('EstimateLow : '+EstimateLow)

      // ## Description
      let Description = await this.platformData.getDescription(page);            
      //console.log('Description : '+Description)

      // ## Fees
      let {feesText, fees} = await this.platformData.getFees(page);

      console.log('feesText : '+feesText)
      console.log('fees : '+fees)
     
      // ################
      // ### SALE

      let {id_sale, urlSale} = await this.platformData.getSaleID(page);

    console.log('SellNumber : '+id_sale)

    
    console.log('url : '+urlSale) 

    let LotInfos = {
      idPlatform: idLot,
      platform : this._Name,
      url: this.Url,
      title: title,
      lotNumber: lotNumber,
      EstimateLow: EstimateLow,
      EstimateHigh: EstimateHigh,
      Description: Description,
      feesText: feesText,
      fees: fees,
      saleInfo: {
        idSale: id_sale,
        url: urlSale
      }
    }

    console.log('LotInfos : '+LotInfos)

    return LotInfos
  }

  getSaleInfos = async ({ page, data}) => {
    console.log("getSaleInfos "+this._Name+":  "+this.Url)
         
    // Navigate the page to a URL            
    await page.goto(this.Url);           

    let {saleID, urlSale} = await this.platformData.getUrlInfo(this.Url);    
    
    console.log('saleID : '+saleID) 
    console.log('urlSale : '+urlSale)
    
    // ## Title    
    let title = await this.platformData.getSaleTitle(page);
    console.log('title : '+title)

    // ## Date
    let date = await this.platformData.getSaleDate(page);
    console.log('date : '+date)
    
    // ## Location
    let location = await this.platformData.getSaleLocation(page);
    console.log('location : '+location)

    // ## SaleHouseName
    let saleHouseName = await this.platformData.getSaleHouseName(page);
    console.log('saleHouseName : '+saleHouseName)
    
    // ## Status
    // ready : ready to be followed 
    // following : sale is followed by the AuctionAgent
    // askStop : sale is followed by the AuctionAgent and the user ask to stop following
    // pause : the Sale is stopped by the Auction House and ready to restart
    // end : the Sale is ended
    // endOnError : the Sale is ended on error
    // endOnRequest: end of follow asked by user

    let status = 'ready'

    let SaleInfo = {
      idPlatform: saleID,
      platform : this._Name,
      url: urlSale,
      title: title,
      date: date,
      location: location,
      saleHouseName: saleHouseName,
      status: status
    }

    console.log('SaleInfo : ', JSON.stringify(SaleInfo, null, 2));
    return SaleInfo
  }

  getLotList = async ({ page, data}) => {
    console.log("getLotList "+this._Name+":  "+this.Url)

    // Navigate the page to a URL            
    await page.goto(this.Url);    
    
    const LotList = await this.platformData.getLotList(page);
    console.log('LotList : '+LotList)
    return LotList
  }

  // ### Playwright
  // ###########################################################################

  async CheckCookieDialog(page) {    
    console.log("-- CheckCookieDialog --")
    return new Promise(async (resolve, reject) => {

      //let XpathCookieButton = "xpath=//button[contains(@class, 'rgpd') and contains(text(), 'Tout refuser')"
      // const CookieButton = await page.$$(XpathCookieButton);      
      const CookieButton = await page.$('//button[contains(@class, "rgpd") and contains(text(), "Tout refuser")]');
      //console.log(CookieButton)
      if (CookieButton && await CookieButton.isVisible()) {
        console.log("-- Click on CookieButton --")
        await CookieButton.click();
      }

      resolve(true)
    })
  }

  async CheckAndConnect(page) {
    
    return new Promise(async (resolve, reject) => {

      await page.goto(this._PAGE_MAIN);
      
      await this.CheckCookieDialog(page);

      console.log("-- CheckConnexion --")
      //get the Connexion button
      
      let XpathConnexion = "//div[contains(@class, 'btn') and contains(@class, 'ghost') and contains(text(), 'Connexion')]"      
      const Connexion = await page.$$(XpathConnexion);
      
      // if Connection button found => Login
      if (Connexion.length > 0) {
        console.log("-- Login --")

        await page.goto(this._PAGE_LOGIN);

        //get the Email field
        //console.log("-- get Email Input --")
        //await page.type('#email', this._USER);
        await page.fill('#email', this._USER);

        //console.log("-- get password Input --")
        //wait page.type("#password", this._PWD);
        await page.fill('#password', this._PWD);
        
        //await page.screenshot({ path: 'screenshot.png', fullPage: true });

        //console.log("-- get ConnexionButton --")
        //const [ConnexionButton] = await page.$x("//button[contains(text(), 'Connexion')]");
        //await ConnexionButton.evaluate(b => b.click());
        await page.click("//button[contains(text(), 'Connexion')]");

        //console.log("-- Login wait --")
        await page.waitForTimeout(1000);
        //resolve(page)
        
        const ConnexionOK = await page.$$("//button[contains(text(), 'Continuer en tant que')]");
        //console.log(ConnexionOK)
        if (ConnexionOK.length > 0) {
                    
          //await ConnexionOK.screenshot({ path: 'screenshot.png', fullPage: true });

          //await ConnexionOK.evaluate(b => b.click());
          await ConnexionOK[0].click();
          await page.waitForTimeout(1000);

          await this._saveSession(page)

          console.log("-- Connection OK --")
          resolve(page)
        } else {
          console.error("-- !!!! Connection ERROR !!!! --");
          reject()
        }

        // Allready connected
      } else {
        console.log("-- Allready connected --")
        resolve(page)
      }
    })

  }

  Live = async (browser) => {

    const context = await this._getContext(browser);
        
    console.log("Live "+this._Name+":  "+this.Url)
        
    let page = await context.newPage();
    
    page = await this.CheckAndConnect(page);

    let lastbid = 0;
    let CloseCount = 0;
        
    //init Protobuf Decoder
    const protobuf = require("protobufjs");
    const root = await protobuf.load(this._PATH_PROTOBUF_FILE);
    const LiveBiddingMessage = root.lookupType("drouot.LiveBiddingMessage");
    
    const listener = async (params) => {
      
      let buffer = params.payload;

      const err = LiveBiddingMessage.verify(buffer);
      if (err) {
          throw err;
      }
      const message = LiveBiddingMessage.decode(buffer);
      const BideMessage = LiveBiddingMessage.toObject(message, {enums: String});
      
      let DataLot = null
      if(BideMessage.vente && BideMessage.vente.lot && BideMessage.vente.lot.lotId != undefined){
        DataLot = await this.platformData.getLiveDataLot(BideMessage.vente.lot.lotId);
      }

      switch (BideMessage.type) {
        case 'PING':
            break;
        case 'PONG':
            break;
        case 'INIT':
          console.log('INIT');
            break;

        case 'CLOSE':          
          console.log('CLOSE');

          //refresh the live to avoid unintoended close
          clearInterval(CheckAskStop);
          CloseCount++;
          
          if(CloseCount > config.agent.maxCloseWebsockets){
            console.log('CloseCount > config.agent.maxCloseWebsockets') 
            StopLive('endOnError')
            return
          }else{
            console.log('Retry #'+CloseCount)
            await GoLive();
          }

            break;
        case 'BID':
          console.log('BID');
          console.log('Lot: '+BideMessage.vente.lot.lotId+' Amount: '+BideMessage.vente.bid.amount);          
          
          lastbid = Date.now();
          
          await this.JucundusBid(
            BideMessage.vente.lot.lotId, 
            Date.now(),                  
            BideMessage.vente.bid.amount, 
            BideMessage.vente.bid.type
          );
            break;

        case 'SELECT_LOT':
          console.log('SELECT_LOT');
          console.log('Lot: '+BideMessage.vente.lot.lotId);

          //console.log('DataLot : '+DataLot)

          await this.JucunduNextItem(
            BideMessage.vente.venteId, 
            Date.now(), 
            BideMessage.vente.lot.lotId, 
            DataLot.num, 
            DataLot.titre, 
            DataLot.description, 
            DataLot.estimationBasse,
            DataLot.estimationHaute,
            DataLot
          );
                    
            break;
        case 'STARTING_PRICE':
          console.log('STARTING_PRICE');

          await this.JucunduNextItem(
            BideMessage.vente.venteId, 
            Date.now(),
            BideMessage.vente.lot.lotId, 
            DataLot.num, 
            DataLot.titre, 
            DataLot.description, 
            DataLot.estimationBasse,
            DataLot.estimationHaute,
            DataLot
          );

            break;
        case 'INCREMENT':
          console.log('INCREMENT');
            break;

        case 'TENDERING':
          console.log('TENDERING');
          console.log('Lot: '+BideMessage.vente.lot.lotId+' Amount: '+BideMessage.vente.bid.amount);

          await this.JucunduAuctionedItem(
            BideMessage.vente.lot.lotId,
            Date.now(),                    
            BideMessage.vente.bid.amount, 
            BideMessage.vente.lot.state == 'ADJ' ? true : false, 
            BideMessage.vente.bid.type
          );
                    
          break;

        case 'GENERIC_MESSAGE':
          console.log('GENERIC_MESSAGE');
            break;
        case 'CREATE_LOT':
          console.log('CREATE_LOT');
            break;
        case 'NOT_INTERESTED':
            break;
        case 'INTERESTED':
            break;
        case 'ACTIVITY':
            break;
        case 'NEW_CLIENT':
          console.log('NEW_CLIENT');
            break;
        case 'CLOSED_CLIENT':
            break;
        case 'KILL':          
            break;
        case 'MULTILOT_REQUEST':
            break;
        case 'MULTILOT_RESPONSE':
            break;
        case 'SYNC_PAYMENT_LIMIT':
            break;
        case 'SWITCH_FREE_BID_AUTHORIZE':
            break;
        case 'REFRESH_CLIENTS_COUNT':
          console.log('REFRESH_CLIENTS_COUNT');
            break;
        default:
            //console.log('Unknown type:', BideMessage);
      }

    };   
    
    let CheckAskStop = null;
    let CheckLastBid = null;
    let Socket = null;
    
    // Stop the Live
    const StopLive = async (code) => {
      clearInterval(CheckAskStop);
      clearInterval(CheckLastBid);

      await this.JucundusEndSale(code)

      page.close()
      browser.close()      
    }

    return
    
    // create the live URL
    let {saleID} = await this.platformData.getUrlInfo(this.Url);    
    let UrlLive = this._PAGE_MAIN + "live/bidlive/" + saleID;
    
    const GoLive = async () => {
      try{      
        console.log('UrlLive : '+UrlLive)
  
        await page.goto(UrlLive, { waitUntil: 'domcontentloaded' });
        
        // intercept Lots Data
        await page.route('https://api.drouot.com/drouot/gingolem/api/live/venteInfos/'+saleID+'?lang=fr', async route => {
          console.log('GetLiveData')
          const response = await route.fetch();
          const LotData = await response.json();
          this.platformData.setLiveData(LotData.data);
          route.continue();
        });
  
        page.on('websocket', ws => {              
          Socket = ws;     
          Socket.on('framereceived', listener);        
          console.log('Websocket connected');
        });
  
        console.log('UrlLive : reload')
        await page.reload();
  
        // check if stop was asked 
        CheckAskStop = setInterval(async () => {
          this.JucundusCheckStop()
          .then(async AskStop => {
            if(AskStop){
              await StopLive('endOnRequest')
              return
            }
          })
        }, 10000); // 10000 milliseconds = 10 seconds

        // Check every minute if the last event is more than 10 minutes ago
        CheckLastBid = setInterval(() => {
          if (lastbid && Date.now() - lastbid > 10 * 60 * 1000) {
            console.log("More than 10 minutes since the last bid.");
            this.JucundusSetSaleStatus(saleInfo, 'end')
            (async () => {
              await StopLive('end');
            })();
            return
          }
        }, 60 * 1000); // 60 seconds = 1 minute
  
      }catch(e){
        console.log('Error : '+e)
        throw new Error('Error: '+e)
      }    

    }

    await GoLive();

  }

  CaptureVideo = async () => {

  }
};


module.exports = Drouot