<?php

namespace App\Entity;

use App\Repository\PlaceRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
// use App\Service\Motocultrice;
#[ORM\Entity(repositoryClass: PlaceRepository::class)]
class Place
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 50)]
    private ?string $uuid_for_url = null;

    #[ORM\Column(length: 10)]
    private ?string $osm_kind = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $email = null;

    #[ORM\Column]
    private ?bool $opted_out = null;

    #[ORM\Column]
    private ?bool $dead = null;

    #[ORM\Column(type: Types::TEXT, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $note = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTime $modified_date = null;

    #[ORM\Column(type: Types::INTEGER)]
    private ?int $zip_code = null;

    #[ORM\Column]
    private ?bool $asked_humains_support = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTime $last_contact_attempt_date = null;

    /**
     * @var Collection<int, History>
     */
    #[ORM\OneToMany(targetEntity: History::class, mappedBy: 'place_id', orphanRemoval: true)]
    private Collection $histories;

    #[ORM\ManyToOne(inversedBy: 'places', cascade: ['persist'])]
    private ?Stats $stats = null;

    #[ORM\Column(type: Types::BIGINT)]
    private ?string $osmId = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $name = null;

    #[ORM\Column(nullable: true)]
    private ?bool $has_opening_hours = null;

    #[ORM\Column(nullable: true)]
    private ?bool $has_address = null;

    #[ORM\Column(nullable: true)]
    private ?bool $has_website = null;

    #[ORM\Column(nullable: true)]
    private ?bool $has_wheelchair = null;

    #[ORM\Column(nullable: true)]
    private ?bool $has_note = null;

    #[ORM\Column(nullable: true)]
    private ?string $main_tag = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $note_content = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTime $displayed_date = null;

    #[ORM\Column(nullable: true, type: Types::FLOAT)]
    private ?float $lat = null;

    #[ORM\Column(nullable: true, type: Types::FLOAT)]
    private ?float $lon = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $street = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' 
=> 'utf8mb4'])]
    private ?string $housenumber = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' 
=> 'utf8mb4'])]
    private ?string $siret = null;

    #[ORM\Column(nullable: true)]
    private ?int $habitants = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTime $osm_data_date = null;

    #[ORM\Column(nullable: true)]
    private ?int $osm_version = null;

    #[ORM\Column(length: 255, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $osm_user = null;

    #[ORM\Column(nullable: true)]
    private ?int $osm_uid = null;

    #[ORM\Column(nullable: true)]
    private ?int $osm_changeset = null;

    #[ORM\Column(type: Types::TEXT, nullable: true, options: ['charset' => 'utf8mb4'])]
    private ?string $emailContent = null;

    #[ORM\Column(type: Types::INTEGER, nullable: true)]
    private ?int $place_count = null;

    public function getPlaceTypeName(): ?string
    {
        if ($this->main_tag == 'amenity=restaurant') {
            return 'restaurant';
        }
        if ($this->main_tag == 'amenity=bar') {
            return 'bar';
        }
        if ($this->main_tag == 'amenity=cafe') {    
            return 'café';
        }
        if ($this->main_tag == 'amenity=hotel') {
            return 'hôtel';
        }
        if ($this->main_tag == 'amenity=supermarket') {
            return 'supermarché';
        }
        if ($this->main_tag == 'amenity=pharmacy') {
            return 'pharmacie';
        }
        if ($this->main_tag == 'amenity=bank') {
            return 'banque';
        }
        if ($this->main_tag == 'amenity=post_office') {
            return 'poste';
        }
        if ($this->main_tag == 'amenity=school') {
            return 'école';
        }

        return 'établissement';
    }

    public function getMainTag(): ?string
    {
        return $this->main_tag;
    }

    public function setMainTag(?string $main_tag): static   
    {
        $this->main_tag = $main_tag;

        return $this;
    }
    

    public function getCompletionPercentage(): ?int
    {
        $completion_percentage = 0;
        $total_fields = 5;
        $filled_fields = 0;
        if ($this->has_opening_hours) {
            $filled_fields += 1;
        }
        if ($this->has_address) {
            $filled_fields += 1;
        }
        if ($this->has_website) {
            $filled_fields += 1;
        }
        if ($this->has_wheelchair) {
            $filled_fields += 1;
        }   
        if ($this->has_note) {
            $filled_fields += 1;
        }
        return round($filled_fields / $total_fields * 100);
    }

    public function guess_main_tag(array $tags_converted) {
        $main_tag = null;
        if (isset($tags_converted['amenity']) && $tags_converted['amenity'] != '') {
            $main_tag = 'amenity='.$tags_converted['amenity'];
        }
        if (isset($tags_converted['shop']) && $tags_converted['shop'] != '') {
            $main_tag = 'shop='.$tags_converted['shop'];
        }
        if (isset($tags_converted['tourism']) && $tags_converted['tourism'] != '') {
            $main_tag = 'tourism='.$tags_converted['tourism'];
        }
        if (isset($tags_converted['office']) && $tags_converted['office'] != '') {
            $main_tag = 'office='.$tags_converted['office'];
        }
        if (isset($tags_converted['healthcare']) && $tags_converted['healthcare'] != '') {
            $main_tag = 'healthcare='.$tags_converted['healthcare'];
        }   
        return $main_tag;
    }
    /**
     * mettre à jour le lieu selon les tags osm
     */
    public function update_place_from_overpass_data(array $overpass_data) {

        if (!isset($overpass_data['tags']) || $overpass_data['tags'] == null) {
            return;
        }
        
        $tags = $overpass_data['tags'];
    
        // Setters for basic properties from top-level of overpass data
        $this->setOsmId($overpass_data['id'])
            ->setOsmKind($overpass_data['type'])
            ->setLat((float) ($overpass_data['lat'] ?? 0))
            ->setLon((float) ($overpass_data['lon'] ?? 0));
    
        // Setters for metadata
        if (isset($overpass_data['timestamp'])) {
            try {
                $this->setOsmDataDate(new \DateTime($overpass_data['timestamp']));
            } catch (\Exception $e) {
                // Ignore if date is invalid
            }
        }
        if (isset($overpass_data['version'])) {
            $this->setOsmVersion($overpass_data['version']);
        }
        if (isset($overpass_data['user'])) {
            $this->setOsmUser($overpass_data['user']);
        }
        if (isset($overpass_data['uid'])) {
            $this->setOsmUid($overpass_data['uid']);
        }
        if (isset($overpass_data['changeset'])) {
            $this->setOsmChangeset($overpass_data['changeset']);
        }
        
        // Guess main tag
        $main_tag = $this->guess_main_tag($tags);
        if ($main_tag) { 
            $this->setMainTag($main_tag);
        }
        
        // Setters from tags
        $this->setName($tags['name'] ?? null);
        
        $street = isset($tags['addr:street']) ? $tags['addr:street'] : (isset($tags['contact:street']) ? $tags['contact:street'] : null);
        $this->setStreet($street);

        $housenumber = isset($tags['addr:housenumber']) ? $tags['addr:housenumber'] : (isset($tags['contact:housenumber']) ? $tags['contact:housenumber'] : null);
        $this->setHousenumber($housenumber);

        if (isset($tags['addr:postcode'])) {
            $this->setZipCode(intval($tags['addr:postcode']));
        }
        
        $email = isset($tags['contact:email']) ? $tags['contact:email'] : (isset($tags['email']) ? $tags['email'] : null);
        $this->setEmail($email);
        
        $siret = isset($tags['ref:FR:SIRET']) ? $tags['ref:FR:SIRET'] : null;
        $this->setSiret($siret);
    
        // Boolean "has" properties
        $this->setHasOpeningHours(!empty($tags['opening_hours']));
        $this->setHasWheelchair(!empty($tags['wheelchair']));
    
        // has address logic

        $this->setHasAddress(!empty($this->getStreet()) && !empty($this->getHousenumber()) 
        | (isset($tags['addr:street']) && isset($tags['addr:housenumber'])) );
        
        // has website logic (with multiple possible tags)
        $websiteTags = ['website', 'contact:website', 'url', 'contact:url'];
        $hasWebsite = false;
        foreach ($websiteTags as $tag) {
            if (!empty($tags[$tag])) {
                $hasWebsite = true;
                break;
            }
        }
        $this->setHasWebsite($hasWebsite);

    
        // has note logic
        $noteContent = '';
        $hasNote = false;
        if (!empty($tags['note'])) {
            $noteContent .= $tags['note'];
            $hasNote = true;
        }
        if (!empty($tags['fixme'])) {
            if ($noteContent !== '') {
                $noteContent .= "\n\n";
            }
            $noteContent .= "FIXME: " . $tags['fixme'];
            $hasNote = true;
        }
        $this->setNoteContent($noteContent ? $noteContent : null);
        $this->setHasNote($hasNote);
        $this->setNote($noteContent);
    }

    public function __construct()
    {
        $this->histories = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getUuidForUrl(): ?string
    {
        return $this->uuid_for_url;
    }

    public function setUuidForUrl(string $uuid_for_url): static
    {
        $this->uuid_for_url = $uuid_for_url;

        return $this;
    }

    public function getOsmKind(): ?string
    {
        return $this->osm_kind;
    }

    public function setOsmKind(string $osm_kind): static
    {
        $this->osm_kind = $osm_kind;

        return $this;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(?string $email): static
    {
        $this->email = $email;

        return $this;
    }

    public function isOptedOut(): ?bool
    {
        return $this->opted_out;
    }

    public function setOptedOut(bool $opted_out): static
    {
        $this->opted_out = $opted_out;

        return $this;
    }

    public function isDead(): ?bool
    {
        return $this->dead;
    }

    public function setDead(bool $dead): static
    {
        $this->dead = $dead;

        return $this;
    }

    public function getNote(): ?string
    {
        return $this->note;
    }

    public function setNote(?string $note): static
    {
        $this->note = $note;

        return $this;
    }

    public function getModifiedDate(): ?\DateTime
    {
        return $this->modified_date;
    }

    public function setModifiedDate(?\DateTime $modified_date): static
    {
        $this->modified_date = $modified_date;

        return $this;
    }

    public function getZipCode(): ?int
    {
        return $this->zip_code;
    }

    public function setZipCode(int $zip_code): static
    {
        $this->zip_code = $zip_code;

        return $this;
    }

    public function isAskedHumainsSupport(): ?bool
    {
        return $this->asked_humains_support;
    }

    public function setAskedHumainsSupport(bool $asked_humains_support): static
    {
        $this->asked_humains_support = $asked_humains_support;

        return $this;
    }

    public function getLastContactAttemptDate(): ?\DateTime
    {
        return $this->last_contact_attempt_date;
    }

    public function setLastContactAttemptDate(?\DateTime $last_contact_attempt_date): static
    {
        $this->last_contact_attempt_date = $last_contact_attempt_date;

        return $this;
    }

    /**
     * @return Collection<int, History>
     */
    public function getHistories(): Collection
    {
        return $this->histories;
    }

    public function addHistory(History $history): static
    {
        if (!$this->histories->contains($history)) {
            $this->histories->add($history);
            $history->setPlaceId($this);
        }

        return $this;
    }

    public function removeHistory(History $history): static
    {
        if ($this->histories->removeElement($history)) {
            // set the owning side to null (unless already changed)
            if ($history->getPlaceId() === $this) {
                $history->setPlaceId(null);
            }
        }

        return $this;
    }

    public function getStats(): ?Stats
    {
        return $this->stats;
    }

    public function setStats(?Stats $stats): static
    {
        $this->stats = $stats;

        return $this;
    }

    public function getOsmId(): ?string
    {
        return $this->osmId;
    }

    public function setOsmId(string $osmId): static
    {
        $this->osmId = $osmId;

        return $this;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(?string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function hasOpeningHours(): ?bool
    {
        return $this->has_opening_hours;
    }

    public function setHasOpeningHours(?bool $has_opening_hours): static
    {
        $this->has_opening_hours = $has_opening_hours;

        return $this;
    }

    public function hasAddress(): ?bool
    {
        return $this->has_address;
    }

    public function setHasAddress(?bool $has_address): static
    {
        $this->has_address = $has_address;

        return $this;
    }

    public function hasWebsite(): ?bool
    {
        return $this->has_website;
    }

    public function setHasWebsite(?bool $has_website): static
    {
        $this->has_website = $has_website;

        return $this;
    }

    public function hasWheelchair(): ?bool
    {
        return $this->has_wheelchair;
    }

    public function setHasWheelchair(?bool $has_wheelchair): static
    {
        $this->has_wheelchair = $has_wheelchair;

        return $this;
    }

    public function hasNote(): ?bool
    {
        return $this->has_note;
    }

    public function setHasNote(?bool $has_note): static
    {
        $this->has_note = $has_note;

        return $this;
    }


    public function getPlaceCount(): ?int
    {
        return $this->place_count;
    }

    public function setPlaceCount(int $place_count): static
    {
        $this->place_count = $place_count;

        return $this;
    }

    public function getNoteContent(): ?string
    {
        return $this->note_content;
    }

    public function setNoteContent(?string $note_content): static
    {
        $this->note_content = $note_content;

        return $this;
    }

    public function getDisplayedDate(): ?\DateTime
    {
        return $this->displayed_date;
    }

    public function setDisplayedDate(?\DateTime $displayed_date): static
    {
        $this->displayed_date = $displayed_date;

        return $this;
    }

    public function getLat(): ?float
    {
        return $this->lat;
    }

    public function setLat(?float $lat): static
    {
        $this->lat = $lat;

        return $this;
    }

    public function getLon(): ?float
    {
        return $this->lon;
    }

    public function setLon(?float $lon): static
    {
        $this->lon = $lon;

        return $this;
    }

    public function getStreet(): ?string
    {
        return $this->street;
    }

    public function setStreet(?string $street): static
    {
        $this->street = $street;

        return $this;
    }

    public function getHousenumber(): ?string
    {
        return $this->housenumber;
    }

    public function setHousenumber(?string $housenumber): static
    {
        $this->housenumber = $housenumber;

        return $this;
    }

    public function getSiret(): ?string
    {
        return $this->siret;
    }

    public function setSiret(?string $siret): static
    {
        $this->siret = $siret;

        return $this;
    }

    public function getHabitants(): ?int
    {
        return $this->habitants;
    }

    public function setHabitants(?int $habitants): static
    {
        $this->habitants = $habitants;

        return $this;
    }

    public function getOsmDataDate(): ?\DateTime
    {
        return $this->osm_data_date;
    }

    public function setOsmDataDate(?\DateTime $osm_data_date): static
    {
        $this->osm_data_date = $osm_data_date;

        return $this;
    }

    public function getOsmVersion(): ?int
    {
        return $this->osm_version;
    }

    public function setOsmVersion(?int $osm_version): static
    {
        $this->osm_version = $osm_version;

        return $this;
    }

    public function getOsmUser(): ?string
    {
        return $this->osm_user;
    }

    public function setOsmUser(?string $osm_user): static
    {
        $this->osm_user = $osm_user;

        return $this;
    }

    public function getOsmUid(): ?int
    {
        return $this->osm_uid;
    }

    public function setOsmUid(?int $osm_uid): static
    {
        $this->osm_uid = $osm_uid;

        return $this;
    }

    public function getOsmChangeset(): ?int
    {
        return $this->osm_changeset;
    }

    public function setOsmChangeset(?int $osm_changeset): static
    {
        $this->osm_changeset = $osm_changeset;

        return $this;
    }

    public function getEmailContent(): ?string
    {
        return $this->emailContent;
    }

    public function setEmailContent(?string $emailContent): static
    {
        $this->emailContent = $emailContent;
        return $this;
    }

    public function toArray(): array
    {
        return [
            'name' => $this->getName(),
            'mainTag' => $this->getMainTag(),
            'housenumber' => $this->getHousenumber(),
            'street' => $this->getStreet(),
            'completionPercentage' => $this->getCompletionPercentage(),
            'lat' => $this->getLat(),
            'lon' => $this->getLon(),
        ];
    }
}
