"use client";

import { RoundedBox } from "@react-three/drei";
import type { ThreeElements } from "@react-three/fiber";
import { useMemo } from "react";

type BuildingProps = ThreeElements["group"] & {
  accent?: string;
};

function Window({
  position,
  scale = [0.8, 0.9, 0.08],
}: {
  position: [number, number, number];
  scale?: [number, number, number];
}) {
  return (
    <mesh position={position} scale={scale} castShadow receiveShadow>
      <boxGeometry />
      <meshPhysicalMaterial
        color="#8fc8e8"
        roughness={0.18}
        metalness={0.15}
        transmission={0.12}
        transparent
        opacity={0.9}
      />
    </mesh>
  );
}

function Door({
  position,
  scale = [0.9, 1.6, 0.12],
}: {
  position: [number, number, number];
  scale?: [number, number, number];
}) {
  return (
    <mesh position={position} scale={scale} castShadow>
      <boxGeometry />
      <meshStandardMaterial
        color="#34596f"
        roughness={0.3}
        metalness={0.2}
      />
    </mesh>
  );
}

function RoofSlab({
  position,
  scale,
}: {
  position: [number, number, number];
  scale: [number, number, number];
}) {
  return (
    <RoundedBox
      position={position}
      args={scale}
      radius={0.12}
      smoothness={4}
      castShadow
      receiveShadow
    >
      <meshStandardMaterial color="#f2f5f6" roughness={0.75} />
    </RoundedBox>
  );
}

export function Villa({
  position = [-7, 0, 2.5],
  rotation = [0, 0, 0],
  scale = 1,
  accent = "#159bd7",
  ...props
}: BuildingProps) {
  return (
    <group
      position={position}
      rotation={rotation}
      scale={scale}
      {...props}
    >
      <RoundedBox
        position={[0, 1.35, 0]}
        args={[5.8, 2.7, 4.5]}
        radius={0.22}
        smoothness={5}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial color="#f8fafb" roughness={0.72} />
      </RoundedBox>

      <RoundedBox
        position={[1.55, 3.05, -0.25]}
        args={[2.45, 1.8, 3.3]}
        radius={0.18}
        smoothness={5}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial color="#edf2f4" roughness={0.72} />
      </RoundedBox>

      <RoundedBox
        position={[-1.25, 2.85, 0.35]}
        args={[2.4, 1.4, 2.7]}
        radius={0.18}
        smoothness={5}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial color="#ffffff" roughness={0.7} />
      </RoundedBox>

      <mesh position={[0, 0.13, 0]} receiveShadow>
        <boxGeometry args={[6.7, 0.25, 5.4]} />
        <meshStandardMaterial color="#d7dfe2" roughness={0.9} />
      </mesh>

      <mesh position={[0, 0.23, 2.72]} receiveShadow>
        <boxGeometry args={[4.4, 0.12, 1.1]} />
        <meshStandardMaterial color="#e9edef" roughness={0.85} />
      </mesh>

      <Door position={[0.25, 1.35, 2.3]} scale={[0.55, 1.35, 0.12]} />

      <Window position={[-1.75, 1.35, 2.3]} scale={[0.8, 0.75, 0.08]} />
      <Window position={[1.75, 1.35, 2.3]} scale={[0.8, 0.75, 0.08]} />
      <Window position={[-1.25, 2.9, 1.75]} scale={[0.65, 0.55, 0.08]} />
      <Window position={[1.55, 3.1, 1.45]} scale={[0.7, 0.75, 0.08]} />

      <mesh position={[0.25, 3.68, 2.12]} castShadow>
        <boxGeometry args={[5.25, 0.15, 0.35]} />
        <meshStandardMaterial color={accent} roughness={0.42} />
      </mesh>

      <RoofSlab position={[1.55, 4.02, -0.25]} scale={[2.8, 0.18, 3.65]} />
      <RoofSlab position={[-1.25, 3.62, 0.35]} scale={[2.75, 0.18, 3.05]} />

      <mesh position={[-2.35, 1.75, 0]} castShadow>
        <boxGeometry args={[0.14, 3.1, 3.9]} />
        <meshStandardMaterial color={accent} roughness={0.4} />
      </mesh>
    </group>
  );
}

function OfficeWindowGrid() {
  const windows = useMemo(() => {
    const items: React.ReactNode[] = [];

    for (let floor = 0; floor < 8; floor += 1) {
      for (let column = 0; column < 4; column += 1) {
        const x = -1.65 + column * 1.1;
        const y = 1.2 + floor * 1.05;

        items.push(
          <Window
            key={`front-${floor}-${column}`}
            position={[x, y, 1.92]}
            scale={[0.42, 0.34, 0.06]}
          />,
        );
      }
    }

    for (let floor = 0; floor < 8; floor += 1) {
      for (let column = 0; column < 3; column += 1) {
        const z = -1.05 + column * 1.05;
        const y = 1.2 + floor * 1.05;

        items.push(
          <mesh
            key={`side-${floor}-${column}`}
            position={[2.22, y, z]}
            scale={[0.06, 0.34, 0.4]}
            castShadow
          >
            <boxGeometry />
            <meshPhysicalMaterial
              color="#8fc8e8"
              roughness={0.18}
              metalness={0.15}
              transmission={0.12}
              transparent
              opacity={0.9}
            />
          </mesh>,
        );
      }
    }

    return items;
  }, []);

  return <>{windows}</>;
}

export function OfficeTower({
  position = [4.5, 0, -4],
  rotation = [0, 0, 0],
  scale = 1,
  accent = "#159bd7",
  ...props
}: BuildingProps) {
  return (
    <group
      position={position}
      rotation={rotation}
      scale={scale}
      {...props}
    >
      <mesh position={[0, 0.14, 0]} receiveShadow>
        <boxGeometry args={[6.2, 0.28, 5.2]} />
        <meshStandardMaterial color="#d8dfe1" roughness={0.9} />
      </mesh>

      <RoundedBox
        position={[0, 4.65, 0]}
        args={[4.6, 9.3, 3.8]}
        radius={0.2}
        smoothness={5}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial color="#f4f7f8" roughness={0.62} />
      </RoundedBox>

      <RoundedBox
        position={[-1.7, 2.25, -1.65]}
        args={[1.45, 4.5, 1.15]}
        radius={0.14}
        smoothness={4}
        castShadow
      >
        <meshStandardMaterial color="#e4eaed" roughness={0.7} />
      </RoundedBox>

      <OfficeWindowGrid />

      <mesh position={[-2.14, 4.9, 0]} castShadow>
        <boxGeometry args={[0.18, 8.2, 3.5]} />
        <meshStandardMaterial color={accent} roughness={0.35} />
      </mesh>

      <mesh position={[0, 9.38, 0]} castShadow receiveShadow>
        <boxGeometry args={[4.9, 0.22, 4.1]} />
        <meshStandardMaterial color="#dce3e6" roughness={0.82} />
      </mesh>

      <mesh position={[0.9, 9.75, 0]} castShadow>
        <boxGeometry args={[1.35, 0.55, 1.2]} />
        <meshStandardMaterial color="#bfcbd0" roughness={0.75} />
      </mesh>

      <Door position={[0, 1.05, 1.94]} scale={[0.75, 1.0, 0.08]} />

      <mesh position={[0, 0.35, 2.55]} receiveShadow>
        <boxGeometry args={[3.2, 0.15, 1.25]} />
        <meshStandardMaterial color="#edf1f3" roughness={0.82} />
      </mesh>

      <mesh position={[0, 1.95, 2.15]} castShadow>
        <boxGeometry args={[2.1, 0.22, 0.45]} />
        <meshStandardMaterial color={accent} roughness={0.4} />
      </mesh>
    </group>
  );
}

export function CommercialBuilding({
  position = [7, 0, 4.5],
  rotation = [0, 0, 0],
  scale = 1,
  accent = "#159bd7",
  ...props
}: BuildingProps) {
  return (
    <group
      position={position}
      rotation={rotation}
      scale={scale}
      {...props}
    >
      <mesh position={[0, 0.13, 0]} receiveShadow>
        <boxGeometry args={[7.7, 0.25, 5.6]} />
        <meshStandardMaterial color="#d6dde0" roughness={0.9} />
      </mesh>

      <RoundedBox
        position={[0, 1.9, 0]}
        args={[6.8, 3.8, 4.7]}
        radius={0.22}
        smoothness={5}
        castShadow
        receiveShadow
      >
        <meshStandardMaterial color="#f8fafb" roughness={0.68} />
      </RoundedBox>

      <RoundedBox
        position={[-2.15, 3.55, -0.35]}
        args={[2.1, 1.5, 3.6]}
        radius={0.16}
        smoothness={5}
        castShadow
      >
        <meshStandardMaterial color="#e9eef0" roughness={0.72} />
      </RoundedBox>

      {[-2.25, -0.75, 0.75, 2.25].map((x) => (
        <Window
          key={x}
          position={[x, 2.05, 2.4]}
          scale={[0.58, 0.92, 0.07]}
        />
      ))}

      <Door position={[0, 1.1, 2.42]} scale={[0.62, 1.05, 0.08]} />

      <mesh position={[0, 3.15, 2.48]} castShadow>
        <boxGeometry args={[6.25, 0.28, 0.34]} />
        <meshStandardMaterial color={accent} roughness={0.38} />
      </mesh>

      <mesh position={[0, 4.0, 0]} castShadow receiveShadow>
        <boxGeometry args={[7.2, 0.2, 5.0]} />
        <meshStandardMaterial color="#dfe6e8" roughness={0.82} />
      </mesh>

      <mesh position={[0, 0.32, 3.1]} receiveShadow>
        <boxGeometry args={[5.9, 0.14, 1.1]} />
        <meshStandardMaterial color="#edf1f3" roughness={0.85} />
      </mesh>

      <mesh position={[2.8, 2.0, 0]} castShadow>
        <boxGeometry args={[0.18, 3.15, 4.1]} />
        <meshStandardMaterial color={accent} roughness={0.38} />
      </mesh>
    </group>
  );
}

export function FuturePlot({
  position = [-1.5, 0, -7.5],
  rotation = [0, 0, 0],
  scale = 1,
  accent = "#159bd7",
  ...props
}: BuildingProps) {
  return (
    <group
      position={position}
      rotation={rotation}
      scale={scale}
      {...props}
    >
      <mesh position={[0, 0.08, 0]} receiveShadow>
        <boxGeometry args={[6.5, 0.16, 4.8]} />
        <meshStandardMaterial color="#e1e6e8" roughness={0.92} />
      </mesh>

      <mesh position={[0, 0.18, 0]} receiveShadow>
        <boxGeometry args={[5.9, 0.12, 4.2]} />
        <meshStandardMaterial color="#c7d8c1" roughness={0.95} />
      </mesh>

      <mesh position={[0, 0.3, 0]} castShadow>
        <boxGeometry args={[4.9, 0.18, 3.2]} />
        <meshStandardMaterial
          color={accent}
          roughness={0.75}
          transparent
          opacity={0.3}
        />
      </mesh>

      {[
        [-2.9, 0.7, -2],
        [2.9, 0.7, -2],
        [-2.9, 0.7, 2],
        [2.9, 0.7, 2],
      ].map((positionValue, index) => (
        <mesh
          key={index}
          position={positionValue as [number, number, number]}
          castShadow
        >
          <cylinderGeometry args={[0.08, 0.08, 1.25, 10]} />
          <meshStandardMaterial color="#7b8a90" roughness={0.7} />
        </mesh>
      ))}

      <mesh position={[0, 1.05, 0]} castShadow>
        <boxGeometry args={[3.8, 0.85, 0.18]} />
        <meshStandardMaterial color="#ffffff" roughness={0.68} />
      </mesh>

      <mesh position={[0, 1.08, 0.1]}>
        <boxGeometry args={[2.8, 0.12, 0.04]} />
        <meshStandardMaterial
          color={accent}
          emissive={accent}
          emissiveIntensity={0.25}
        />
      </mesh>
    </group>
  );
}

export default function Buildings() {
  return (
    <group>
      <Villa />
      <OfficeTower />
      <CommercialBuilding />
      <FuturePlot />
    </group>
  );
}
