import Web3 from 'web3';
import { Suspense, useState, useEffect } from 'react';
import { Canvas } from '@react-three/fiber';
import {  Environment, MapControls } from '@react-three/drei';
import {  Physics } from '@react-three/cannon';
import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import Ground from './components/Ground';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { useThree } from '@react-three/fiber';
import { MeshReflectorMaterial } from "@react-three/drei";

// Import CSS
import './App.css';

// Import Components
import Navbar from './components/Navbar';

// Import ABI
import Land from './abis/Land.json';

function App() {
	const [web3, setWeb3] = useState(null)
	const [account, setAccount] = useState(null)

	// Contract & Contract States
	const [landContract, setLandContract] = useState(null)

	const [cost, setCost] = useState(0)
	const [buildings, setBuildings] = useState(null)
	const [landId, setLandId] = useState(null)
	const [landName, setLandName] = useState(null)
	const [landOwner, setLandOwner] = useState(null)
	const [hasOwner, setHasOwner] = useState(false)

	const loadBlockchainData = async () => {
		//controlliamo che l'utente abbia installato metamask
		if (typeof window.ethereum !== 'undefined') {
			const web3 = new Web3(window.ethereum)
			setWeb3(web3)

			const accounts = await web3.eth.getAccounts()
			

			//verifichiamo che la lunghezza dell'account sia maggiore di 0
			if (accounts.length > 0) {
				//settiamo il primo account trovato
				setAccount(accounts[0])
			}

			const networkId = await web3.eth.net.getId()
			
			//otteniamo il contratto presente sulla blockchain
			//Land abi rappresenta il contratto in formato json
			const land = new web3.eth.Contract(Land.abi, Land.networks[networkId].address)
			setLandContract(land)

			//settiamo il costo con una visualizzazione in ether e non in wei
			const cost = await land.methods.cost().call()
			setCost(web3.utils.fromWei(cost.toString(), 'ether'))

			const buildings = await land.methods.getBuildings().call()
			setBuildings(buildings)

			// Event listeners...
			//ogni volta che cambio account imposterò il primo della lista come attivo
			window.ethereum.on('accountsChanged', function (accounts) {
				setAccount(accounts[0])
			})

			//ricarichiamo se cambia la blockchain utilizzata su metamask
			window.ethereum.on('chainChanged', (chainId) => {
				window.location.reload();
			})
		}
	}

	// MetaMask Login/Connect
	const web3Handler = async () => {
		if (web3) {
			const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
			setAccount(accounts[0])
		}
	}

	useEffect(() => {
		loadBlockchainData()
	}, [account])

	const buyHandler = async (_id) => {
		try {
			await landContract.methods.mint(_id).send({ from: account, value: '1000000000000000000' })

			const buildings = await landContract.methods.getBuildings().call()
			setBuildings(buildings)

			setLandName(buildings[_id - 1].name)
			setLandOwner(buildings[_id - 1].owner)
			setHasOwner(true)
		} catch (error) {
			window.alert('Error occurred when buying')
		}
	}


	const palazzoCentrale = useLoader(GLTFLoader, "models/Acquistabili/palazzoCentrale.glb");
	const parco = useLoader(GLTFLoader, "models/Acquistabili/parco.glb");
	const palazzoGiustizia = useLoader(GLTFLoader, "models/Acquistabili/palazzoDiGiustizia.glb");
	const palazzoReale = useLoader(GLTFLoader, "models/Acquistabili/palazzoReale.glb");
	const palazzoGenerale = useLoader(GLTFLoader, "models/Acquistabili/palazzoGenerale.glb");
	const palazzoTecnologico = useLoader(GLTFLoader, "models/Acquistabili/palazzoTecnologico.glb"); 
	const stadio = useLoader(GLTFLoader, "models/Acquistabili/stadio.glb"); 
	const casino = useLoader(GLTFLoader, "models/Acquistabili/casino.glb"); 
	const albergo = useLoader(GLTFLoader, "models/Acquistabili/hotel.glb"); 
	const ristorante = useLoader(GLTFLoader, "models/Acquistabili/ristorante.glb"); 

	
	const CameraController = () => {
		const { camera, gl } = useThree();
		useEffect(
		  () => {
			const controls = new OrbitControls(camera, gl.domElement);
			
			
			controls.minDistance = 200;
			controls.maxDistance = 500;

			controls.minPolarAngle = 0;
			controls.maxPolarAngle = Math.PI*0.4;
			controls.enablePan = false;
			return () => {
			  controls.dispose();
			};
		  },
		  [camera, gl]
		);
		return null;
	  };



	  const closeModal = () => {
		setLandId(null);
	  }
	  

	  



	return (
		<div>
			<Navbar web3Handler={web3Handler} account={account} />
		
			<Canvas shadows camera={{ position: [0, 300, 400]}}>
				<CameraController />
				<Suspense fallback={null}>
					
					<Environment 
						files={process.env.PUBLIC_URL + "/textures/Ground/cielo.hdr"}
						background={"both"}
					/>
					{/*<Lights />*/}

					
								
					<Physics>
			
						{buildings && buildings.map((building, index) => {

							const clickHandler = () => {
								setLandName(building.name)
								setLandId(index + 1)

								if (building.owner === '0x0000000000000000000000000000000000000000') {
									setLandOwner('No Owner')
									setHasOwner(false)
								} else {
									setLandOwner(building.owner)
									setHasOwner(true)
								}
							}

							

							if (building.owner === '0x0000000000000000000000000000000000000000') {
										
								return (							
										<mesh 
											onClick={clickHandler}
											rotation-x={Math.PI * -0.5}
											scale={[building.sizeX, building.sizeY, building.sizeZ]}
											key={index}
											position={[building.posX, 0.7, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<planeGeometry />
											<MeshReflectorMaterial color={"#25AEEC"} />
										</mesh>								
								)
							} else {
								if(building.name === "Palazzo Centrale"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.025,0.025, 0.025]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={palazzoCentrale.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Parco Nord"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*2}
											scale={[1.5,2,1.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={parco.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Parco Sud"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI}
											scale={[1.5,2,1.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={parco.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Parco Ovest"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*0.5}
											scale={[1.5,2,1.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={parco.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Parco Est"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*-0.5}
											scale={[1.5,2,1.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={parco.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Palazzo Di Giustizia"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.5, 0.5, 0.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={palazzoGiustizia.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Palazzo Reale"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.5, 0.5, 0.5]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={palazzoReale.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Palazzo Generale"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.018, 0.018, 0.018]}
											key={index}
											position={[building.posX, 0, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={palazzoGenerale.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Palazzo Tecnologico"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.7, 1, 0.7]}
											key={index}
											position={[building.posX, 0.2, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={palazzoTecnologico.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Stadio"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											
											scale={[0.012, 0.015, 0.012]}
											key={index}
											position={[building.posX, 0.2, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={stadio.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Sala Giochi"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*0.4}
											scale={[0.4, 0.4, 0.4]}
											key={index}
											position={[building.posX, 0.2, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={casino.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Ristorante"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*0.6}
											scale={[1.3, 2, 1.3]}
											key={index}
											position={[building.posX, 0.5, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={ristorante.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else if(building.name === "Albergo"){
									return (	
										<object3D>
										<mesh 
											onClick={clickHandler}
											rotation-y={Math.PI*0.8}
											scale={[5, 5, 5]}
											key={index}
											position={[building.posX, 0.2, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<primitive object={albergo.scene.clone()} />
										</mesh>	
										</object3D>
									)
								}
								else{
									return (	
										<mesh 
											onClick={clickHandler}
											rotation-x={Math.PI * -0.5}
											scale={[building.sizeX, building.sizeY, building.sizeZ]}
											key={index}
											position={[building.posX, 10, building.posZ]}
											landId={index + 1}
											landInfo={building}
											setLandName={setLandName}
											setLandOwner={setLandOwner}
											setHasOwner={setHasOwner}
											setLandId={setLandId}
										>
											<boxBufferGeometry />
											<meshStandardMaterial color={"#ffffff"} />
										</mesh>	
									)
									}	
							}
						})}
					</Physics>

					<Ground/>
				</Suspense>
				{/*<MapControls />*/}
			</Canvas>
			
			{landId && (
				<div className="info">
					<h2 className="flex">{landName}</h2>
					<div className='flex'>
						<div className='info--id'>
							<h3>ID</h3>
							<p>{landId}</p>
						</div>

						<div className='info--owner'>
							<h3>Owner</h3>
							<p>{ landOwner.slice(0, 8) + '...' + landOwner.slice(36, 42)}</p>
						</div>

						{!hasOwner && (
							<div className='info--owner'>
								<h3>Cost</h3>
								<p>{`${cost} ETH`}</p>
							</div>
						)}
					</div>

					{!hasOwner && (
						<button onClick={() => buyHandler(landId)} className='button info--buy'>Buy Property</button>
					)}

					{hasOwner && landName === "Palazzo Centrale" && (
						<a href="https://www.spatial.io/s/VarGroup-633eb35756b230000156eca3?share=6728909407832214510" className='button'>Go To experience</a>
					)}
					
					{hasOwner && (landName === "Parco Nord" || landName === "Parco Ovest" || landName === "Parco Sud" || landName === "Parco Est") && (
						<a href="https://www.spatial.io/s/Spazio-generale-632b395a959f24000150e3fd?share=5944334509030065290" className='button'>Go To experience</a>
					)}
					
					{hasOwner && (landName === "Palazzo di Giustizia" || landName === "Palazzo Reale" || landName === "Palazzo Generale" || landName === "Palazzo Tecnologico") && (
						<a href="https://www.spatial.io/s/Auditorium-VarGroup-6339907d154ac30001eb13e4?share=31206885067101731" className='button'>Go To experience</a>
					)}
					{hasOwner && landName === "Stadio" && (
						<a href="https://www.spatial.io/s/Hublot-Loves-Football-Stadium-6364326afa31ac0001f7a9f6?share=4975564101027278539" className='button'>Go To experience</a>
					)}
					{hasOwner && landName === "Sala Giochi" && (
						<a href="https://www.spatial.io/s/VarGroup-Lab-6336c76163996a0001aedead?share=2343210746006167392" className='button'>Go To experience</a>
					)}
					{hasOwner && landName === "Ristorante" && (
						<a href="https://www.spatial.io/s/Carmeloas-Immersive-World-6346dd7c98c2ca0001427529?share=510814101105934881" className='button'>Go To experience</a>
					)}
					{hasOwner && landName === "Albergo" && (
						<a href="" className='button'>Go To experience</a>
					)}
						<button onClick={() => closeModal()} className='button-close info--buy'>Close</button>
				</div>
			)}
		</div>
	);
}

export default App;