/*
 This file is part of TALER
 (C) 2015-2016 GNUnet e.V.
 TALER is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.
 TALER is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 You should have received a copy of the GNU General Public License along with
 TALER; see the file COPYING.  If not, see 
 */
/**
 * Page shown to the user to confirm creation
 * of a reserve, usually requested by the bank.
 *
 * @author Florian Dold
 */
import { AmountJson, Amounts, ExchangeListItem, GetExchangeTosResult, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util';
import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw';
import { useState } from "preact/hooks";
import { Fragment } from 'preact/jsx-runtime';
import { CheckboxOutlined } from '../components/CheckboxOutlined';
import { ExchangeXmlTos } from '../components/ExchangeToS';
import { LogoHeader } from '../components/LogoHeader';
import { Part } from '../components/Part';
import { SelectList } from '../components/SelectList';
import { ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction, WarningText } from '../components/styled';
import { useAsyncAsHook } from '../hooks/useAsyncAsHook';
import {
  acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges, getExchangeTos
} from "../wxApi";
import { wxMain } from '../wxBackend.js';
interface Props {
  talerWithdrawUri?: string;
}
export interface ViewProps {
  details: GetExchangeTosResult;
  withdrawalFee: AmountJson;
  exchangeBaseUrl: string;
  amount: AmountJson;
  onSwitchExchange: (ex: string) => void;
  onWithdraw: () => Promise;
  onReview: (b: boolean) => void;
  onAccept: (b: boolean) => void;
  reviewing: boolean;
  reviewed: boolean;
  confirmed: boolean;
  terms: {
    value?: TermsDocument;
    status: TermsStatus;
  };
  knownExchanges: ExchangeListItem[];
};
type TermsStatus = 'new' | 'accepted' | 'changed' | 'notfound';
type TermsDocument = TermsDocumentXml | TermsDocumentHtml | TermsDocumentPlain | TermsDocumentJson | TermsDocumentPdf;
interface TermsDocumentXml {
  type: 'xml',
  document: Document,
}
interface TermsDocumentHtml {
  type: 'html',
  href: URL,
}
interface TermsDocumentPlain {
  type: 'plain',
  content: string,
}
interface TermsDocumentJson {
  type: 'json',
  data: any,
}
interface TermsDocumentPdf {
  type: 'pdf',
  location: URL,
}
function amountToString(text: AmountJson) {
  const aj = Amounts.jsonifyAmount(text)
  const amount = Amounts.stringifyValue(aj)
  return `${amount} ${aj.currency}`
}
export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) {
  const needsReview = terms.status === 'changed' || terms.status === 'new'
  const [switchingExchange, setSwitchingExchange] = useState(undefined)
  const exchanges = knownExchanges.reduce((prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), {})
  return (
    
      
      
        {i18n.str`Digital cash withdrawal`}
      
      
        
        
        {Amounts.isNonZero(withdrawalFee) &&
          
        }
        
      
      {!reviewing &&
        
          {switchingExchange !== undefined ? 
            
              
            
             onSwitchExchange(switchingExchange)}>
              {i18n.str`Confirm exchange selection`}
            
          
            :  setSwitchingExchange("")}>
              {i18n.str`Switch exchange`}
            }
        
      }
      {!reviewing && reviewed &&
        
           onReview(true)}
          >
            {i18n.str`Show terms of service`}
          
        
      }
      {terms.status === 'notfound' &&
        
          
            {i18n.str`Exchange doesn't have terms of service`}
          
        
      }
      {reviewing &&
        
          {terms.status !== 'accepted' && terms.value && terms.value.type === 'xml' &&
            
              
            
          }
          {terms.status !== 'accepted' && terms.value && terms.value.type === 'plain' &&
            
          }
          {terms.status !== 'accepted' && terms.value && terms.value.type === 'html' &&
            
          }
          {terms.status !== 'accepted' && terms.value && terms.value.type === 'pdf' &&
            Download Terms of Service
          }
        }
      {reviewing && reviewed &&
        
           onReview(false)}
          >
            {i18n.str`Hide terms of service`}
          
        
      }
      {(reviewing || reviewed) &&
        
           {
              onAccept(!reviewed)
              onReview(false)
            }}
          />
        
      }
      {/**
       * Main action section
       */}
      
        {terms.status === 'new' && !reviewed && !reviewing &&
           onReview(true)}
          >
            {i18n.str`Review exchange terms of service`}
          
        }
        {terms.status === 'changed' && !reviewed && !reviewing &&
           onReview(true)}
          >
            {i18n.str`Review new version of terms of service`}
          
        }
        {(terms.status === 'accepted' || (needsReview && reviewed)) &&
          
            {i18n.str`Confirm withdrawal`}
          
        }
        {terms.status === 'notfound' &&
          
            {i18n.str`Withdraw anyway`}
          
        }
      
    
  )
}
export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriInfo: WithdrawUriInfoResponse }) {
  const [customExchange, setCustomExchange] = useState(undefined)
  const [errorAccepting, setErrorAccepting] = useState(undefined)
  const [reviewing, setReviewing] = useState(false)
  const [reviewed, setReviewed] = useState(false)
  const [confirmed, setConfirmed] = useState(false)
  const knownExchangesHook = useAsyncAsHook(() => listExchanges())
  const knownExchanges = !knownExchangesHook || knownExchangesHook.hasError ? [] : knownExchangesHook.response.exchanges
  const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount)
  const thisCurrencyExchanges = knownExchanges.filter(ex => ex.currency === withdrawAmount.currency)
  const exchange = customExchange || uriInfo.defaultExchangeBaseUrl || thisCurrencyExchanges[0]?.exchangeBaseUrl
  const detailsHook = useAsyncAsHook(async () => {
    if (!exchange) throw Error('no default exchange')
    const tos = await getExchangeTos(exchange, ['text/xml'])
    const info = await getExchangeWithdrawalInfo({
      exchangeBaseUrl: exchange,
      amount: withdrawAmount,
      tosAcceptedFormat: ['text/xml']
    })
    return { tos, info }
  })
  if (!detailsHook) {
    return Getting withdrawal details.;
  }
  if (detailsHook.hasError) {
    return Problems getting details: {detailsHook.message};
  }
  const details = detailsHook.response
  const onAccept = async (): Promise => {
    try {
      await setExchangeTosAccepted(exchange, details.tos.currentEtag)
      setReviewed(true)
    } catch (e) {
      if (e instanceof Error) {
        setErrorAccepting(e.message)
      }
    }
  }
  const onWithdraw = async (): Promise => {
    setConfirmed(true)
    console.log("accepting exchange", exchange);
    try {
      const res = await acceptWithdrawal(uri, exchange);
      console.log("accept withdrawal response", res);
      if (res.confirmTransferUrl) {
        document.location.href = res.confirmTransferUrl;
      }
    } catch (e) {
      setConfirmed(false)
    }
  };
  const termsContent: TermsDocument | undefined = parseTermsOfServiceContent(details.tos.contentType, details.tos.content);
  const status: TermsStatus = !termsContent ? 'notfound' : (
    !details.tos.acceptedEtag ? 'new' : (
      details.tos.acceptedEtag !== details.tos.currentEtag ? 'changed' : 'accepted'
    ))
  return 
}
export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element {
  const uriInfoHook = useAsyncAsHook(() => !talerWithdrawUri ? Promise.reject(undefined) :
    getWithdrawalDetailsForUri({ talerWithdrawUri })
  )
  if (!talerWithdrawUri) {
    return missing withdraw uri;
  }
  if (!uriInfoHook) {
    return Loading...;
  }
  if (uriInfoHook.hasError) {
    return This URI is not valid anymore: {uriInfoHook.message};
  }
  return 
}
function parseTermsOfServiceContent(type: string, text: string): TermsDocument | undefined {
  if (type === 'text/xml') {
    try {
      const document = new DOMParser().parseFromString(text, "text/xml")
      return { type: 'xml', document }
    } catch (e) {
      console.log(e)
      debugger;
    }
  } else if (type === 'text/html') {
    try {
      const href = new URL(text)
      return { type: 'html', href }
    } catch (e) {
      console.log(e)
      debugger;
    }
  } else if (type === 'text/json') {
    try {
      const data = JSON.parse(text)
      return { type: 'json', data }
    } catch (e) {
      console.log(e)
      debugger;
    }
  } else if (type === 'text/pdf') {
    try {
      const location = new URL(text)
      return { type: 'pdf', location }
    } catch (e) {
      console.log(e)
      debugger;
    }
  } else if (type === 'text/plain') {
    try {
      const content = text
      return { type: 'plain', content }
    } catch (e) {
      console.log(e)
      debugger;
    }
  }
  return undefined
}