import { promises as fs } from 'fs';
import * as path from 'path';
import * as xml2js from 'xml2js';
import moment from 'moment';

const readFile = fs.readFile;
// const writeFile = fs.writeFile;
// const readdir = fs.readdir;
// const copyFile = fs.copyFile;
// const mkdir = fs.mkdir;

export declare type TCurrencyCode = 'USD' | 'CAD' | 'GBP';
export declare type TCountriesIncluded = 'CA' | 'GB' | 'AT' | 'BE' | 'CY' | 'DE' | 'EE' | 'ES' | 'FI' | 'FR' | 'GR' | 'IE' | 'IT' | 'LT' | 'LU' | 'LV' | 'MT' | 'NL' | 'PT' | 'SI' | 'SK';
export declare type TTranslator = 'Babel Novel' | 'Lemon Novel' | 'Fancy Novel';

export declare interface IBookPrice {
  currencyCode: TCurrencyCode;
  priceAmount: number;
  countriesIncluded: TCountriesIncluded[] | ['WORLD'];
}

export declare interface IBookOnixInfo {
  bookName: string;
  description: string;
  author: string;
  volume: number;
  translator: TTranslator;
  isbn: string;
  subjectCode: string;
  price: IBookPrice[];
  keywords: string[];
  subTitle?: string;
  publicationDate?: string;
  preOrderDate?: string;
  salesRestriction?: 'ALL' | 'TOP_FIVE' | 'KINDLE_ONLY';
  pageCount?: number;
  takedown?: boolean;
}

export declare interface IBookChapter {
  title: string;
  content: string[];
}

export declare interface IinitOption {
  senderName: string;
  contactName: string;
  emailAddress: string;
  cityOfPublication: string;
  countryOfManufacture: TCountriesIncluded | 'CN';
  publisherName: string;
  websiteLink: string;
}

export const xml2jsParser = async (text: string): Promise<any> => {
  const parser = new xml2js.Parser();
  return new Promise((resolve, reject) => {
    parser.parseString(text, (err: any, result: any) => {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  });
};

export class ONIXGenerator {
  private initOption: IinitOption = {
    senderName: 'Funstory',
    contactName: 'Funstory',
    emailAddress: 'email@email.com',
    cityOfPublication: 'BeiJing',
    countryOfManufacture: 'CN',
    publisherName: 'Funstory',
    websiteLink: 'https://funstory.ai',
  };
  private tempObj: any;

  constructor(initOption: IinitOption) {
    if (initOption) {
      this.initOption = initOption;
    }
    this.tempObj = '';
  }

  public async init(initOption?: IinitOption) {
    if (initOption) {
      this.initOption = initOption;
    }
    // 读取ONIX模板xml
    const onixTmp = await readFile(path.join(__dirname, `./onixTmp.xml`));
    // ONIX模板xml2js
    this.tempObj = await xml2jsParser(onixTmp.toString('utf8'));
  }

  public getTemp() {
    return this.tempObj;
  }

  public genONIX(bookinfo: IBookOnixInfo): string {

    if (this.tempObj === '') {
      throw new Error('please run init() first');
    }

    const onixObj = {...this.tempObj};
    onixObj.ONIXMessage.Header[0].Sender[0].SenderName = this.initOption.senderName;
    onixObj.ONIXMessage.Header[0].Sender[0].ContactName = this.initOption.contactName;
    onixObj.ONIXMessage.Header[0].Sender[0].EmailAddress = this.initOption.emailAddress;
    // onixObj.ONIXMessage.Product[0].DescriptiveDetail[0]
    //   .CountryOfManufacture = this.initOption.countryOfManufacture;
    onixObj.ONIXMessage.Product[0].PublishingDetail[0]
      .Publisher[0].PublisherName = this.initOption.publisherName;
    onixObj.ONIXMessage.Product[0].PublishingDetail[0]
      .Publisher[0].Website[0].WebsiteLink = this.initOption.websiteLink;
    onixObj.ONIXMessage.Product[0].PublishingDetail[0]
      .CityOfPublication = this.initOption.cityOfPublication;
    onixObj.ONIXMessage.Product[0].PublishingDetail[0]
      .CountryOfPublication = this.initOption.countryOfManufacture;
    onixObj.ONIXMessage.Product[0].ProductSupply[0]
      .SupplyDetail[0].Supplier[0].SupplierName = this.initOption.publisherName;

    // ISBN
    const isbnNum = bookinfo.isbn;
    onixObj.ONIXMessage.Product[0].RecordReference = isbnNum;
    onixObj.ONIXMessage.Product[0].ProductIdentifier[0].IDValue = isbnNum;

    // 书名
    const bookTitle = bookinfo.bookName;
    const volumeNum = bookinfo.volume;
    const subTitle = bookinfo.subTitle;

    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].TitleDetail[0]
      .TitleElement[0].TitleText = `${bookTitle}`;
    // 副标题
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].TitleDetail[0]
      .TitleElement[0].Subtitle = subTitle ? subTitle : `Book ${volumeNum}`;
    // 第几卷(系列号)
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Collection[0]
      .CollectionSequence[0].CollectionSequenceNumber = volumeNum;
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Collection[0]
      .TitleDetail[0].TitleElement[0].TitleText = `Book ${volumeNum}`;

    // 作者
    const bookAuthor = bookinfo.author.split(' ');
    const familyName1 = bookAuthor.shift() || '';
    const familyName = familyName1[0] ? `${familyName1[0].toUpperCase()}${familyName1.slice(1)}` : '';
    const authorName1 = bookAuthor.join('');
    const authorName = authorName1[0] ? `${authorName1[0].toUpperCase()}${authorName1.slice(1)}` : '';
    // onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].KeyNames = bookAuthor;
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].PersonName = `${familyName} ${authorName}`;
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].PersonNameInverted = `${authorName}, ${familyName}`;

    // 译者
    const bookTranslator = bookinfo.translator.split(' ');
    if (bookTranslator.length > 0) {
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[1].PersonName = `${bookTranslator[0]} ${bookTranslator[1]}`;
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[1].PersonNameInverted = `${bookTranslator[1]}, ${bookTranslator[0]}`;
    }

    const bookPageCount = bookinfo.pageCount;
    if (bookPageCount) {
      // onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent = [{}];
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentType = '00';
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentValue = bookPageCount;
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentUnit = '03';
    } else {
      delete onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent;
    }

    // 小说类型  详见https://bisg.org/page/Fiction ['FIC008000', 'FIC009000', 'FIC028000']
    const aBISACEdition = bookinfo.subjectCode;
    onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[0].SubjectCode = aBISACEdition;

    // 关键词
    const bookKeywords = bookinfo.keywords;
    if (bookKeywords.length > 0) {
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[1] = {};
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[1].SubjectSchemeIdentifier = 20;
      onixObj.ONIXMessage.Product[0].DescriptiveDetail[0]
        .Subject[1].SubjectHeadingText = bookKeywords.join('; ');
    }

    // 小说简介
    const description = bookinfo.description.replace(/(\r|\n)+/g, '').trim();
    onixObj.ONIXMessage.Product[0].CollateralDetail[0].TextContent[0].Text[0]._ = description;

    const nowdate = moment();
    const publicationDate = bookinfo.publicationDate ? moment(bookinfo.publicationDate) : nowdate;
    const preOrderDate = bookinfo.preOrderDate ? moment(bookinfo.preOrderDate) : undefined;
    const publicationDateTime = parseInt(publicationDate.format('x'), 10);
    const nowDateTime = parseInt(nowdate.format('x'), 10);
    // 是否未发布  根据发布日期是否大于当前日期对比
    const noPublushed: boolean = publicationDateTime > nowDateTime;
    // 发送日期
    onixObj.ONIXMessage.Header[0].SentDateTime = nowdate.format('YYYYMMDDTHHmm');
    // 出版日期
    onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[0] = {
      PublishingDateRole: ['01'],
      Date: [{
        $: { dateformat: '00' },
        _: publicationDate.format('YYYYMMDD'),
      }],
    };
    // 解禁日期
    onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[1] = {
      PublishingDateRole: ['02'],
      Date: [{
        $: { dateformat: '00' },
        _: publicationDate.format('YYYYMMDD'),
      }],
    };
    // 上市日期
    onixObj.ONIXMessage.Product[0].ProductSupply[0].
      MarketPublishingDetail[0].MarketDate[0].Date[0]._ = publicationDate.format('YYYYMMDD');
    // 是否可用 10	Not yet available, 20	Available
    onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0]
      .ProductAvailability[0] = noPublushed ? '10' : '20';

    // 出版状态 04 Active, 02	Forthcoming
    onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingStatus[0] = noPublushed ? '02' : '04';
    onixObj.ONIXMessage.Product[0].ProductSupply[0].MarketPublishingDetail[0].MarketPublishingStatus[0] = noPublushed ? '02' : '04';

    // 预售信息
    if (preOrderDate && (parseInt(preOrderDate.format('x'), 10) < publicationDateTime)) {
      // 预售日期
      onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[2] = {
        PublishingDateRole: ['09'],
        Date: [{
          $: { dateformat: '00' },
          _: preOrderDate.format('YYYYMMDD'),
        }],
      };
    }
    // if (noPublushed) {
    //   onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate = [];
    //   onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate[0] = {
    //     SupplyDateRole: '02',
    //     Date: [{
    //       $: { dateformat: '00' },
    //       _: publicationDate.format('YYYYMMDD'),
    //     }],
    //   };
    //   onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate[1] = {
    //     SupplyDateRole: '08',
    //     Date: [{
    //       $: { dateformat: '00' },
    //       _: publicationDate.format('YYYYMMDD'),
    //     }],
    //   };
    // }

    const salesRestriction = bookinfo.salesRestriction || 'KINDLE_ONLY';
    switch (salesRestriction) {
      case 'KINDLE_ONLY':
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
          SalesRestrictionType: ['04'],
          SalesOutlet: [
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['AMZ']
              }],
              SalesOutletName: ['Amazon eBookBase']
            },
          ],
        };
        break;
      case 'TOP_FIVE':
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
          SalesRestrictionType: ['04'],
          SalesOutlet: [
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['AMZ']
              }],
              SalesOutletName: ['Amazon eBookBase']
            },
            // {
            //   SalesOutletIdentifier: [{
            //     SalesOutletIDType: ['03'],
            //     IDValue: ['BNO']
            //   }],
            //   SalesOutletName: ['Barnes And Noble']
            // },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['GOO']
              }],
              SalesOutletName: ['Google Books']
            },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['APC']
              }],
              SalesOutletName: ['iBookstore']
            },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['KBO']
              }],
              SalesOutletName: ['Kobo']
            },
          ],
        };
        break;
      default:
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
        onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
          SalesRestrictionType: ['04'],
          SalesOutlet: [
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['AMZ']
              }],
              SalesOutletName: ['Amazon eBookBase']
            },
            // {
            //   SalesOutletIdentifier: [{
            //     SalesOutletIDType: ['03'],
            //     IDValue: ['BNO']
            //   }],
            //   SalesOutletName: ['Barnes And Noble']
            // },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['GOO']
              }],
              SalesOutletName: ['Google Books']
            },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['APC']
              }],
              SalesOutletName: ['iBookstore']
            },
            {
              SalesOutletIdentifier: [{
                SalesOutletIDType: ['03'],
                IDValue: ['KBO']
              }],
              SalesOutletName: ['Kobo']
            },
          ],
        };
        break;
    }

    // 地区及当地价格
    const priceInfo = bookinfo.price;
    onixObj.ONIXMessage.Product[0].ProductSupply[0]
      .SupplyDetail[0].Price = priceInfo.map((price: any) => ({
        PriceType: '01',
        PriceStatus: '01',
        PriceAmount: price.priceAmount,
        CurrencyCode: price.currencyCode,
        Territory: [
          (price.countriesIncluded.length === 1 && price.countriesIncluded[0] === 'WORLD') ? (
            {
              RegionsIncluded: price.countriesIncluded[0],
              CountriesExcluded: 'CN',
            }
          ) : (
              {
                CountriesIncluded: price.countriesIncluded.join(' '),
              }
            )
        ]
      }));
    // 返回ONIX xml

    // 下架ONIX
    if (bookinfo.takedown){
      onixObj.ONIXMessage.Product[0].NotificationType[0] = '04';
      onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0]
        .ProductAvailability[0] = '51';
      onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingStatus[0] = '07';
      onixObj.ONIXMessage.Product[0].ProductSupply[0].MarketPublishingDetail[0]
        .MarketPublishingStatus[0] = '07';
    }


    const js2xmlBuilder2 = new xml2js.Builder({ renderOpts: { pretty: true } });
    return js2xmlBuilder2.buildObject(onixObj);
  }
}
