import './App.css';
import { read, utils } from "xlsx";
import { ethers, parseEther,formatEther  } from "ethers";
import { useCallback, useEffect, useRef, useState } from 'react';
import { Table } from './component/table';
import { getBalance, multisend } from './utile/blockchain';
import { divide } from './utile/chunk';
import { setComma } from './utile/setComma';
import { List } from './component/list';

function App() {

  const [from, setFrom] = useState("");
  const [provider, setProvider] = useState();
  const tokenRef = useRef(null);
  const [chunkArray, setChunkArray] = useState([]);
  const [selectedChunks, setSelectedChunks] = useState([]); // 선택된 청크 인덱스 배열
  const [balance, setBalance] = useState(0);
  const [totalAmount, setTotalAmount] = useState(0);

  const handleFile = (file) => {
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (evt) => {
      try {
        const data = new Uint8Array(evt.target.result);
        const workbook = read(data, { type: 'array' });
        const sheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[sheetName];
        const jsonData = utils.sheet_to_json(worksheet, {raw:true});

        if (jsonData.length === 0) {
          alert("파일에 데이터가 없습니다.");
          return;
        }

        const columns = Object.keys(jsonData[0]);
        const requiredColumns = ['address', 'amount'];

        if (columns.length !== 2 ||
            !requiredColumns.every(col => columns.includes(col))) {
          alert("양식이 맞지 않습니다.");
          return;
        }

        let total = totalAmount;

        const filteredData = jsonData.filter(row => {
          if (typeof row.address !== "string" ||
              row.address.toUpperCase().includes("EX") ||
              String(row.amount).toUpperCase().includes("EX")) {
            return false;
          }

          try {
            ethers.getAddress(row.address.split("\r\n").join("").trim());   
            return true;
          } catch (error) {
            console.warn(`Invalid address: ${row.address}`, error);
            return false;
          }
        });

        const addresses = filteredData.map((row) => {
          const a = row.address;
          return a;
        });
        const amount = filteredData.map((row) => {
          const rounded = Math.round(Number(row.amount) * 100) / 100;
          total += rounded
          return parseEther(rounded.toFixed(2));
        });
        
        setChunkArray(prev => [...prev, ...divide(addresses, amount)]);
        console.log(total)
        setTotalAmount(total)

      } catch (error) {
        console.error("Error:", error);
        alert(error)
      }
      
    };
    reader.readAsArrayBuffer(file);
  };

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    handleFile(file);
  };

  const handleDragOver = (e) => {
    e.preventDefault();
  };

  const handleDrop = (e) => {
    e.preventDefault();
    const file = e.dataTransfer.files[0];
    handleFile(file);
  };

  useEffect(()=>{
    if (!window.ethereum) return alert("MetaMask not installed");
    setProvider(new ethers.BrowserProvider(window.ethereum))
  },[])

  
  const walletProvider = useCallback(async ()=>{
    try {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain',
        params: [{ chainId: '0x38' }] //0x38
      });
    } catch (err) {
      await window.ethereum.request({
        method: 'wallet_addEthereumChain',
        params: [{
          chainId: '0x38', //0x38
          chainName: 'BNB Smart Chain Mainnet',
          rpcUrls: ['https://binance.llamarpc.com'],
          nativeCurrency: { 
            name: 'BNB',
            symbol: 'BNB',
            decimals: 18
          },
          blockExplorerUrls: ['https://bscscan.com/']
        }]
      });
    }
    
    await provider.send("eth_requestAccounts", []);

    window.ethereum.on("accountsChanged", (accounts) => {
      if (accounts.length > 0) {
        setFrom(accounts[0]);
      } else {
        setFrom(null);
      }
    });
    const signer = provider.getSigner();    
    const senderAddress = await signer;

    const tokenAddress = tokenRef.current?.value;
    const balance = await getBalance(tokenAddress, provider, senderAddress)

    setBalance(balance)
    setFrom(senderAddress.address)

  },[provider])
  
  useEffect(()=>{
    if(provider){
      walletProvider()
    }

    return () => {
      if (window.ethereum?.removeListener) {
        window.ethereum.removeListener("accountsChanged", () => {});
        window.ethereum.removeListener("chainChanged", () => {});
      }
    };

  },[provider, walletProvider])

  // 체크박스 토글
  const toggleChunkSelection = (idx) => {
    if (chunkArray[idx].status === 0) return;

    setSelectedChunks(prev => {
      if (prev.includes(idx)) {
        return prev.filter(i => i !== idx); 
      } else {
        return [...prev, idx]; 
      }
    });
  };

  const sendToken = async () => {
    const tokenAddress = tokenRef.current?.value;
    let failedIdxs = [];

    for (const idx of selectedChunks) {
      const chunk = chunkArray[idx];

      try {
        const status = await multisend(
          tokenAddress,
          provider,
          from,
          chunk.chunkAddresses,
          chunk.chunkAmounts
        );

        if (status) {
          setChunkArray(prev => prev.map((c, i) =>
            i === idx ? {...c, status: 0} : c
          ));
        } else {
          setChunkArray(prev => prev.map((c, i) =>
            i === idx ? {...c, status: 1} : c
          ));
          failedIdxs.push(idx)
         
        }
      } catch (error) {
        console.error(`Chunk ${idx + 1} 전송 실패:`, error);
        alert(`Chunk ${idx + 1} 전송 중 오류가 발생했습니다.`);
        break;
      }
    }
    // 전송 완료 
    setSelectedChunks(failedIdxs);
  };

  return (
    <div className="App">      
      <div className="wrap">
        <fieldset>
          <legend>UPLOAD</legend>

          <ul>
            <li>
              <label htmlFor="tokenAddress">토큰 컨트랙트</label>
              <input type="text" id="tokenAddress" defaultValue="0x36b8dE7c6B06B3f170003452114f0B8E6BcFEE18" ref={tokenRef}/>
            </li>
            
            <li>
              <label htmlFor="contract">발송 주소</label>
              <input type="text" id="contract" value={from} disabled/>
            </li>

            <li>
              <div onDragOver={handleDragOver} onDrop={handleDrop}>
                <label htmlFor="file">보내는 계좌</label>
                <input type="file" id="file" accept=".xls,.xlsx,.csv" onChange={handleFileChange}  onDrop={handleDrop} onDragOver={handleDragOver}/>
                <label htmlFor="file"></label>
              </div>
            </li>
          </ul>
          <p>balance : {setComma(formatEther(balance))}</p>
          <p>totalAmount : {setComma(totalAmount)}</p>

          <List chunkArray={chunkArray} selectedChunks={selectedChunks} toggleChunkSelection={toggleChunkSelection}></List>

          <button
            className='transferButton'
            type='button'
            onClick={sendToken}
            disabled={selectedChunks.length === 0}
            style={{
              opacity: selectedChunks.length === 0 ? 0.5 : 1,
              cursor: selectedChunks.length === 0 ? "not-allowed" : "pointer"
            }}
          >
            전송 ({selectedChunks.length})
          </button>
          
        </fieldset>

        <fieldset>
          <legend>DETAIL</legend>

          <div className="flex-row">
            {selectedChunks.length > 0 ? (
              <Table
                addresses={selectedChunks.flatMap(idx => chunkArray[idx].chunkAddresses)}
                amounts={selectedChunks.flatMap(idx => chunkArray[idx].chunkAmounts)}
              />
            ) : ''}
          </div>
        </fieldset>
      </div>
    </div>
  );
}

export default App;

