import {getType, getInst, getSymbol, Double, Int, symbolFunction, symbolProduct, symbolSum, symbolDict, symbolSet, symbolList, eqType, match, getLeft, getRight, dict, Bool, set, Unit, symbolType, symbolUUID, getHumanReadableName} from "dope2";

import "./Value.css";
import { Type } from "./Type";

export function Value({dynamic}) {
  const type = getType(dynamic);
  const inst = getInst(dynamic);
  if (eqType(type)(Double)) {
    return <ValueDouble val={inst}/>;
  }
  if (eqType(type)(Int)) {
    return <ValueInt val={inst}/>;
  }
  if (eqType(type)(Bool)) {
    return <ValueBool val={inst}/>;
  }
  if (eqType(type)(Unit)) {
    return <ValueUnit/>;
  }

  const symbol = getSymbol(type);
  switch (symbol) {
    case symbolFunction:
      return <ValueFunction/>;
    case symbolSum:
      return <ValueSum val={inst} leftType={type.params[0](type)} rightType={type.params[1](type)}/>;
    case symbolProduct:
      return <ValueProduct val={inst} leftType={type.params[0](type)} rightType={type.params[1](type)}/>;
    case symbolDict:
      return <ValueDict val={inst} keyType={type.params[0](type)} valueType={type.params[1](type)}/>;
    case symbolSet:
      return <ValueSet val={inst} elemType={type.params[0](type)} />;
    case symbolList:
      return <ValueList val={inst} elemType={type.params[0](type)} />;
    case symbolType:
      return <Type type={inst}/>;
    case symbolUUID:
      return <ValueUUID val={inst}/>
    default:
      return <>don't know how to show value</>;
  }
}

function ValueDouble({val}) {
  return <span className="valuePrimitive">{val.toString()}</span>;
}
function ValueInt({val}) {
  return <span className="valuePrimitive">{val.toString()}</span>;
}
function ValueFunction() {
  return <>&#119891;&#119899;&nbsp;</>;
}
function ValueBool({val}) {
  return <span className="valuePrimitive">{val.toString()}</span>;
}
function ValueList({val, elemType}) {
  return <span className="listType">[{val.map((v, i) => <Value key={i} dynamic={{i:v, t:elemType}}/>)}]</span>;
}
function ValueSet({val, elemType}) {
  return <span className="setType">{'{'}{set.fold(acc => elem => acc.concat([elem]))([])(val).map((v, i) => <Value key={i} dynamic={{i:v, t:elemType}}/>)}{'}'}</span>;
}
function ValueDict({val, keyType, valueType}) {
  return <span className="dictType">{'{'}{dict.fold(acc => key => value => acc.concat([[key,value]]))([])(val).map(([key, value], i) => <span key={i}>
      <Value dynamic={{i:key, t:keyType}}/>
      &rArr;
      <Value dynamic={{i:value, t:valueType}}/>
    </span>)}{'}'}</span>;
}
function ValueSum({val, leftType, rightType}) {
  return match(val)
    (l => <span className="sumType">L <Value dynamic={{i:l, t:leftType}}/></span>)
    (r => <span className="sumType">R <Value dynamic={{i:r, t:rightType}}/></span>);
}
function ValueProduct({val, leftType, rightType}) {
  return <span className="productType">(<Value dynamic={{i:getLeft(val), t:leftType}}/>,&nbsp;<Value dynamic={{i:getRight(val), t:rightType}} />)</span>;
}
function ValueUnit() {
  return <>{'()'}</>;
}
function ValueUUID({val}) {
  return <span className="valueUUID">{getHumanReadableName(val)}</span>;
}