<?php

namespace App\Clients;

use GuzzleHttp\Client;

class ItgApiClient
{

    const AUTH_URL = 'oauth/token';
    private string $accessToken;
    private Client $client;

    public function __construct(
        readonly private string $baseUrl,
        readonly private string $clientId,
        readonly private string $clientSecret,
        readonly private string $adminBaseUrl
    ) {
        $this->client = new Client([
            'base_uri' => $this->baseUrl,
            'headers' => [
                'Accept' => 'application/json'
            ]
        ]);
        $this->accessToken = $this->authenticateAsClient();
    }

    public function authenticateAsClient(): string
    {
        $params = [
            'grant_type' => 'client_credentials',
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'scope' => '*'
        ];
        return $this->authenticate($params);
    }

    private function authenticate(array $params): string
    {
        $response = $this->client->request('POST', self::AUTH_URL, ['json' => $params]);
        $json = json_decode($response->getBody()->getContents());
        return $json->access_token;
    }

    public function authenticateAsUser(int $userId): string
    {
        $params = [
            'grant_type' => 'user_impersonation_grant',
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,
            'user_id' => $userId
        ];
        return $this->authenticate($params);
    }

    public function setAccessToken(string $accessToken)
    {
        $this->accessToken = $accessToken;
    }

    public function getExhibifyFairByCode(string $code)
    {
        $uri = 'api/private/exhibify_fairs/' . $code . '?language='. app()->getLocale();
        $response = $this->client->request('GET', $uri, [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function register(array $accountData)
    {
        $multipart = array_map(function ($value, $key) {
            if ($key !== 'gallery_main_image') {
                $data = [
                    'name' => $key,
                    'contents' => $value
                ];
            } else {
                $data = [
                    'name' => $key,
                    'contents' => (!empty($value) ? fopen($value, 'r') : '')
                ];
            }
            if ($key === 'gallery_main_image') {
                $data['filename'] = pathinfo($value, PATHINFO_BASENAME);
            }
            return $data;
        }, $accountData, array_keys($accountData));
        $response = $this->client->request('POST', 'api/private/accounts', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'multipart' => $multipart
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function createMagicLink(int $userId)
    {
        $response = $this->client->request('POST', 'api/private/auth/magic_tokens', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'user_id' => $userId
            ]
        ]);
        return json_decode($response->getBody()->getContents())->magic_link;
    }

    public function createExposition(array $expositionData)
    {
        $multipart = array_map(function ($value, $key) {
            $data = [
                'name' => $key,
                'contents' => $key !== 'main_image' ? $value : fopen($value, 'r'),
            ];
            if ($key === 'main_image') {
                $data['filename'] = pathinfo($value, PATHINFO_BASENAME);
            }
            return $data;
        }, $expositionData, array_keys($expositionData));

        $response = $this->client->request('POST', 'api/expositions', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'multipart' => $multipart

        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getUserEmailByDomain(string $domain): array
    {
        $response = $this->client->request(
            'GET',
            'api/private/users/email_domains/' . $domain,
            [
                'headers' => [
                    'Authorization' => 'Bearer ' . $this->accessToken
                ],
            ]
        );
        return json_decode($response->getBody()->getContents());
    }

    public function userExists(string $username)
    {
        $response = $this->client->request('POST', 'api/private/users/check_email', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'email' => $username
            ]
        ]);
        return json_decode($response->getBody()->getContents())->user_exists;
    }

    public function getAdminBaseUrl()
    {
        return $this->adminBaseUrl;
    }

    public function getExpositionsForFairAndGallery(int $fairId, int $galleryId)
    {
        $response = $this->client->request('GET', "api/exhibify_fairs/$fairId/expositions?gallery_id=$galleryId", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getExpositionsForGallery(int $galleryId, string $search = null)
    {
        $response = $this->client->request('GET', "api/expositions", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'query' => [
                'gallery_id' => $galleryId,
                'name' => $search ?? '',
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getExposition(int $expositionId)
    {
        $response = $this->client->request('GET', "api/expositions/$expositionId", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function assignExpositionToExhibifyFair($expositionId, $exhibifyFairId)
    {
        $response = $this->client->request('POST', "api/expositions/$expositionId/exhibify_fairs", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'exhibify_fair_id' => $exhibifyFairId
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function createArtist(array $artistData)
    {
        $response = $this->client->request('POST', 'api/artists', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => $artistData
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function createWork(array $workData)
    {
        $multipart = [];
        foreach ($workData as $key => $value) {
            if ($key === 'main_image') {
                $multipart[] = [
                    'name' => $key,
                    'contents' => fopen($value, 'r'),
                    'filename' => pathinfo($value, PATHINFO_BASENAME)
                ];
            } elseif ($key === 'prices') {
                if (empty($value)) {
                    $multipart[] = [
                        'name' => 'prices',
                        'contents' => ''
                    ];
                }
                foreach ($value as $priceIndex => $priceData) {
                    $multipart[] = [
                        'name' => "prices[$priceIndex][price]",
                        'contents' => $priceData['price']
                    ];
                    $multipart[] = [
                        'name' => "prices[$priceIndex][currency]",
                        'contents' => $priceData['currency']
                    ];
                }
            } elseif ($key === 'dimensions') {
                foreach ($value as $dimensionIndex => $dimensionData) {
                    $multipart[] = [
                        'name' => "dimensions[$dimensionIndex][width]",
                        'contents' => $dimensionData['width']
                    ];
                    $multipart[] = [
                        'name' => "dimensions[$dimensionIndex][height]",
                        'contents' => $dimensionData['height']
                    ];
                    $multipart[] = [
                        'name' => "dimensions[$dimensionIndex][depth]",
                        'contents' => $dimensionData['depth']
                    ];
                    $multipart[] = [
                        'name' => "dimensions[$dimensionIndex][unit]",
                        'contents' => $dimensionData['unit']
                    ];
                }
            } else {
                $multipart[] = [
                    'name' => $key,
                    'contents' => $value
                ];
            }
        }
        $response = $this->client->request('POST', 'api/works', [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'multipart' => $multipart
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function addWorkToExposition(int $workId, int $expositionId)
    {
        $response = $this->client->request('POST', "api/expositions/$expositionId/works", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'work_ids' => [$workId]
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getArtistsByName(string $name, int $galleryId)
    {
        $response = $this->client->request('GET', "api/artists?complete_name=$name&gallery_id=$galleryId", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getGalleryExhibifyIntegration($galleryId)
    {
        $response = $this->client->request('GET', "api/galleries/{$galleryId}/integrations", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'query' => [
                'integration_app_type' => 'exhibify'
            ]
        ]);
        $json = json_decode($response->getBody()->getContents());
        return !empty($json) ? $json[0] : [];
    }

    public function createGalleryExhibifyIntegration($galleryId)
    {
        $response = $this->client->request('POST', "api/galleries/$galleryId/integrations", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'integration_app_type' => 'exhibify'
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getExpositionExhibifyIntegration($expositionId)
    {
        $respones = $this->client->request('GET', "api/expositions/{$expositionId}/integrations", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'query' => [
                'integration_app_type' => 'exhibify'
            ]
        ]);
        return json_decode($respones->getBody()->getContents());
    }

    public function createExpositionExhibifyIntegration(
        $expositionId,
        $galleryIntegrationId,
        $fairCollectionId,
        $workIntegrationData = []
    ) {
        $response = $this->client->request('POST', "api/expositions/$expositionId/integrations", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'json' => [
                'integration_id' => $galleryIntegrationId,
                'integration_data' => [
                    $galleryIntegrationId => [
                        $expositionId => [
                            'send_to_fair' => $fairCollectionId,
                            'work_integration_data' => $workIntegrationData
                        ]
                    ]
                ]
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getWorksForGallery(mixed $galleryId, mixed $search)
    {
        $response = $this->client->request('GET', "api/works", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'query' => [
                'gallery' => $galleryId,
                'search' => $search
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }

    public function getWorkEditionsForGallery(mixed $galleryId, mixed $search)
    {
        $response = $this->client->request('GET', "api/work_editions", [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->accessToken
            ],
            'query' => [
                'gallery_id' => $galleryId,
                'search' => $search
            ]
        ]);
        return json_decode($response->getBody()->getContents());
    }


}
